CHAPTER ONE APPLICATIONS DEVELOPED INA FEW HOURS Ring is a new programming language that focuses on the Natural Language Programming and Declarative Program- ming paradigms and will let you think different about programming and how to solve your problems in a better way. In little days after the first release we got thousands of downloads and many developers started learning and using the language. Their feedback are the secret behind the language progress and success. They said that Ring is powerful, beautiful and easy to learn, Some of them provided good examples about what can be done using Ring in a few hours. They are very happy with the language productivity. 1.1 Quotes about Ring “I like Smalltalk very much but now I like Ring better!” , Gal Zsolt (Hungary) “I find the language and its syntax very natural and easy to follow.” , Bhudda (United States) “Very nice approach for a new language.” , Matth Moestl (Austria) “Very interesting! I will keep an eye on it!” , Eslipak (Argentina) “I’d like to see some benchmarks. Otherwise, at first glance, it looks really promising.” , Alex Deva (Sweden) “Excellent” , Liju Sankar (United States) “I wish you the best with this project.” , David O’Neil (United States) “Just fantastic.” 1
41.
Ring Documentation, Release1.16 , Jose Antonio (Mexico) “This looks like it was developed by some very competent people.” , Jim Clack (United States) “The Ring programming language seems pretty interesting so far.” , Eric Johnson (United States) “Thank you for this awesome language and wonderful ready to use Qt binding.” , Martial FAESSEL “I think it’s great what he does for the community of developers and novice programming.” , Marino Esteban “Ring is just awesome. The language is so cool and fluent. I am sure it’s going to be BIG.” , Ahmed Zain “What a proud, really wish you Eng. Mahmoud Samir and Your Team moving forward ^_^ and from now , considered me a big fan of the Ring programming language.” , Zainab Mahmoud “Well guys I love this language and it appears that you have created perfect language.” , Moemen Ghulmi “Good work Mahmoud, I’ve installed ring pl, and it’s very perfect language.” , Ahmed Omar (Egypt) “Thanks for this great startup programming language. I wish you best of luck.” , Elkhouaja Khalid “Congratulations! I am very happy and I wish you Success and good luck.” , Abobasmla Hassan “Good Features of multi-use language on the Web, Mobile and Desktop.” , Abdelrhman Haider “Very interesting effort.” , Giannakakis Kostas (Greece) 1.1. Quotes about Ring 2
42.
Ring Documentation, Release1.16 “I am too lazy to open comment window and write message. But in your case I must say (Perfect) Really, create new remarkable language like your Ring is really perfect job. Even create editor for your language in your language with only few rows... Even noticed in rosettacode.org ! I read your previous articles and I tried these examples a few days ago and I will continue. I love Ring. P.S.: Anders Hejlsberg, Niklaus Wirth, Bjarne Stroustrup, Ada Lovelace Hall of fame is waiting....” , Martin Nedopil (Czech Republic ) “Ring seems very attractive to me through its very easy design and the Qt bindings. I like its declarative approach and the generous documentation.” , Shalok Shalom (Austria) “Ring (and plenty of extension library + Qt) is wonderful.” , Kovacs Attila (Hungary) “Since two days I’m trying Ring and I’m really impressed, in add to power commands and easy use, it’s really very efficient and very fast. Each day I hope to find the couple of the year PWCT+RING ... Maybe for my Christmas gift!!!! HO HO HO HO Continue your fantastic job and congratulations.” , Jose Le Roux (France) “There are 3 different styles, it looks like Python and C” , 64remy “I was taking a tour around Rosettacode and have found Ring. I like the syntax a lot. It’s clean and easy to understand. It looks like a very clean BASIC dialect without sigils. I can say that this is the easiest and the most BASIC-like language I’ve ever tried.” , Tomaaz “Thanks for your effort. I took a quick look and found it interesting. You are trying to follow more or less like Clipper with simple command and no rigid declaration rules. Good.” , Anand Gupta “Thanks for this wonderful language” , Vinod kc (India) “Very enlightening. good job!” , Southmountain (United States) “The thing I liked was the loop exiting” , Leon de boer (Australia) “An outstanding and easy language to program with.” , Kenneth Burgo (Philippines) 1.1. Quotes about Ring 3
43.
Ring Documentation, Release1.16 “I chose your language as I feel I can understand it better than other languages” , Harry Singh “I like the totality of the language, far more features than expected and the freedom of expressiveness is unique.” , Evikone “Thank you very much Mahmoud! I am using ring for many experiments and so far I love it. I really want to continue using ring and contribute what I can.” , John (SienSystem) “Sir, Very Good” , Kamlesh Patel “That’s more than a “cool” syntax, the example of writing free-form text between curly-brackets such that each word calls a function. Which could be interesting (A syntax like that would be nice for declaring text styles)” , LaurieCheers “If you browse around you see they have listed 160 contributors. This year they have entered Top 100 in the TIOBE index. Lot of effort seem to have been made to make this language pop out and catch the attention of masses.” , Htuhola “I like the idea of The Ring being in ANSI C it’s an impressive creation, and a lot of skill went into it” , Garry Taylor “Very innovative language! Syntactically clean” , CodeProject Member “The author must be commended for the readily-obvious hard work and effort that has gone into creating a rich ecosystem for his language. It seems that the language is quite extensive as well. I would find it useful to see a BNF grammar and concise coverage of its semantics.” , Xx-Leninist-1917-Xx (Reddit) “I can see the AI of the future using this technology to solve computational problems for..... the humans.” , Cryptonite (United States) “I like your programming language, I like you are going to develop mobile app using RingQt and also I appreciate your web library.” , Domenico D’Oria (Italy) 1.1. Quotes about Ring 4
44.
Ring Documentation, Release1.16 “Congratulations for the great work with this new programming language.” , Kenny Silva (Venezuela) “Ring is an amazingly full-featured language and so well documented (the bane of most newer languages out there!)” , Alex McCullie ” I found the language yesterday, and liked the Qt bindings, as they give a declarative way to create a QtWidgets GUI.” , Cochise Cesar “Ring does look intriguing, and I’ll be reading more of the documentation soon” , Jamie Cooper “I was recently considering designing my own dynamically-typed, prototypical language and then developing a means to compile it into C/C++. However, last night I was surfing the web and noticed a little-known language called “Ring” which you’ve recently created. I began reading the Motivation section in Wikibooks to see why the language was designed and implemented, and I was shocked to see that someone else had created a language with the same intention and need as myself. I mean, it’s mind-blowing that someone would have addressed every issue I have with the currently accepted languages. It’s crazy to think it’s only been around for a year and yet, it’s already, practically a batteries-included language.” , Gedalya (YouTube) “Thank you Mr. Mahmoud for all the wonderful work, whenever I dive in the Source code I see the great effort, further development more excellence, God will reward you with what you wish” , Azzedine Ramal “What a great joy to find this surprisingly genius language !!!. It was a total joy to go through the documentation and look at the samples in Rosetta code. Marvelous work. I would even leave my fortune to the development of this language. Keep the good work going and wishing this language will go viral. ps: Thanks for keeping array index to start with 1. It means a lot.” , Nehemiah Jacob (Sydney, Australia) “I find it very interesting. Especially the fact that it is cross platform makes it something to keep an eye on.” , Boudewijn Lutgerink “The language I like the most. Efficient, simple, easy, flexible and wonderful language.” , Roshan Ali “I like variety. The richer the toolbox, the more appropriate the tool.” , Jonathan Day (Quora) 1.1. Quotes about Ring 5
45.
Ring Documentation, Release1.16 “I greatly appreciated your work and congratulations on what has been achieved.” , Umberto Meglio (Italy) “Thanks a lot I just found Ring two days ago and I decided to learn it, it is amazing, the samples are helping a lot.” , Zaraki Ken “Extraordinary. well done sir” , RugbyLeague (CodeProject Member - United Kingdom) “The Ring language is pleasant. You get ahead very quickly.” , Neskuk (CodeProject Member - Switzerland) “I’m happy to use your language.” , Akhil Reddy “I am enjoying using the Ring Programming language.” , Gabriel Wendt “I’m loving this language!” , Pablo Prieto “Ring Notepad is a an example of the power of Ring. It is like NotePad++ with built in form design capability, drag and drop, object attributes etc. It is a marvelous application” , Bert Mariani (Italy) “Ring is the language that offers the greatest potential for converting programmers frustrated with the amount of time it takes to develop apps in C/C++, C# and other OOP-based languages. Considering the extent to which Ring has evolved since the first release in 2016, the Ring team has proven itself worthy of a very high achievement award in the world of programming languages. The extent to which Ring has simplified the development database apps, web apps and GUI apps is a great credit to the Ring team. Ring’s implementation of OOP and GUI based apps is far superior to C++ and C#. Another major achievement of the Ring team is the ease at which programmers can get on-line access to Ring documentation, compared to on-line C++ and C# documentation. The Ring Game Engine is truly elegant and it’s designer (s) deserve lots of credit for such an impressive bit of software.” , L Godioleskky “Strongly speaking, it is a strong and new game programming language.” , isVowel (Japan) “The language seems to have some interesting features, specially the use of braces to access object fields and methods.” 1.1. Quotes about Ring 6
46.
Ring Documentation, Release1.16 , Nuaua (Reddit) “The code that implements the Ring VM actually looks quite nice. There is a bunch of test code – great!” , Peterfirefly (Reddit) “Ring seems promising. It first appeared in 2016 although it’s concept is older. It is meant to be portable and can be embedded in C/C++ projects” , Wim ten Brink (Quora - Top Writer (2018)) “Interesting alternative to Lua.” , djxtc (Sourceforge) “Ring is a serious thing in the programming language landscape. One should understand its foundation before she can shape an opinion worth considering. There are several innovations outthere with a clear commitment from its designer to simplicity, flexibility and learnability. Natural language as its imagined by Ring opens a window for an unlimited set of applications otherwise impossible to think about. One can built an interactive chatbot based on a rich domain specific language in a matter of hours not months. Combined with a smart yet effective implementation of a declarative programming paradigm, Ring empowers the creation of any kind of programming language on top of it, with any set of syntax. Even the language keywords can be overwritten to serve one’s own keywords in any human language not only english. Ring is a disruption, a big intellectual step forward but also a beautiful reincarnation of several legacy ideas and best practices from other old languages like Basic, Lisp and others. Those ideas are a humanity heritage that new visionaries like Mahmoud S. Fayed, the Ring designer, but also Rick Hickey, the Clojure designer, are trying to callback in today’s world of complex programmability. An other dimension of Ring, which formed one of its basic motivations, relates to visual programming. Software is a fluid and evolutionary creature and textual code is not accessible to the most of common humans. The promise of visual programming is to empower people, enhance understandability and invite business users to the arena of software development more intuitively. Ring was made by design with an objective of having a programming language capable of better supporting the visual paradigm. Gamification is a first-class citizen in the language. This is a tremendous advantage compared to other general-purpose programming languages. Ring supports a large number of gaming libraries and open a large window of capabilities to use, not only in gaming but also in business and education applications. The best way to assessing the power of Ring is to looking into it and reflecting about the number of problems it is capable to solve.” , Mansour Ayouni (Tunisia) “I have only known ring-lang for few weeks, really love features and visions of ring: bracket access, class region, declarative and natural programming. It’s simple and beautiful the way ring deal with these paradigms. I think it’s really great work what you’re done, and doing. I want to develop ethereum client in ring language, not only but it’s style. It’ll have natural and declarative code on it’s main part. Furthermore, It will be fantastic if there is “natural language -> evm bytecode” compiler, maybe ring have the solution” , Asta “The language looks great!” , Eric Hawk “You put a lot of work in the Ring and you’re a great programmer. I saw your examples in 3D I’ve looked at 1.1. Quotes about Ring 7
47.
Ring Documentation, Release1.16 part of your project, it’s really great” , Rafal Jopek “Looks like a big project and an impressive piece of work” , Rochus Keller (PhD From ETH Zurich, Switzerland) “I see Ring a very useful and easy in PROGRAMMING IN REGIONAL LANGUAGE. I tried to program in my mother language Hindi ( India) using UNICODE It is working. No other language give me such an easy platform.” , Negi Manoj (India) “I’m glad I could help improve the Ring language. It has good and yet easy to understand design and architecture. I believe it has big potential ahead.” , Mounir IDRASSI (Creator of VeraCrypt) “What I like most about Ring Lang is its ease to create complex applications in WebAssembly.” , Luis Lozad “I just discovered Ring today and immediately liked it and decided to give it a try. As a senior JAVA / ADA and Python developer I am very curious about the multi-paradigm” , Bertrand Pivaty “Wow, that is pretty amazing! It’s not every day to hear about a new programming language that looks actually cool! Oh wow, didn’t even see the VB-like features there. This has some real potential!” , EternityForest (reddit) “I am a big fan of your works I look forward to contributing to some of your projects in the future.” , Adewale Azeez (Nigeria) “I am a software development manager working in a Canadian Firm. I have been around for 25 years playing with different Programming languages like Python, Perl, VB, C#, Java, REBOL, Euphoria etc. Thanks a lot for the wonderful software and the great documentations” , Lijo Joseph (Canada) 1.1. Quotes about Ring 8
48.
Ring Documentation, Release1.16 1.2 FetchStockData Application It will fetch stock data from Yahoo and draw various types of charts. 1.3 Google API Shortener Application A small but very nice tool to shorten urls using the Google shortener API. 1.2. FetchStockData Application 9
49.
Ring Documentation, Release1.16 1.4 Video-Music-Player Application An application to play multi-media files. 1.4. Video-Music-Player Application 10
50.
Ring Documentation, Release1.16 1.5 Fifteen Puzzle Game An implementation for the Fifteen Puzzle game. 1.5. Fifteen Puzzle Game 11
Ring Documentation, Release1.16 1.6 Analog Clock Simple implementation for the Analog Clock. 1.6. Analog Clock 13
53.
Ring Documentation, Release1.16 1.7 Squares Puzzle Game An implementation for the popular Squares Puzzle game. 1.8 Samples in this book The next samples are developed in a few hours and we will introduce them through this book. The next screen shot for the Ring Notepad application 1.7. Squares Puzzle Game 14
54.
Ring Documentation, Release1.16 The next screen shot for the Cards Game The next screen shot for the Cards Game (Android) 1.8. Samples in this book 15
55.
Ring Documentation, Release1.16 The next screen shot from the Web Development chapter 1.8. Samples in this book 16
56.
Ring Documentation, Release1.16 The next screen shots for simple 2D Games that we will present in the Game Engine Chapter. Stars Fighter Game Flappy Bird 3000 Game 1.8. Samples in this book 17
Ring Documentation, Release1.16 The next screen shot for the TicTacToe 3D Game Screen Shot: 1.8. Samples in this book 19
59.
Ring Documentation, Release1.16 The next screen shot for the Gold Magic 800 Game The next screen shot from the RingQt3D chapter 1.8. Samples in this book 20
60.
Ring Documentation, Release1.16 1.9 Innovative The language comes with better support for Natural Language Programming and Declarative Programming. The inno- vation comes in supporting these paradigms with new practical techniques on the top of Object-Oriented Programming and Functional Programming. No need to know anything about (Compilers and Parsing). You get the language con- structs ready for use to create domain-specific languages in a fraction of time. Articles:- • Natural Language Programming Library : https://www.codeproject.com/Articles/1200766/Using-the-Natural-Language-Programming-Library-NLP • Natural Language Programming : https://www.codeproject.com/Articles/1138605/Natural-Language-Programming-in-the-Ring-Programmi • The Declarative Approach : https://www.codeproject.com/Articles/1222105/The-declarative-approach-of-the-Ring-programming-l • Syntax Flexibility : https://www.codeproject.com/Articles/1137388/Syntax-Flexibility-in-the-Ring-Programming-Languag • The Ring Programming Language : https://www.codeproject.com/Articles/1089887/The-Ring-Programming-Language 1.9. Innovative 21
61.
Ring Documentation, Release1.16 1.10 Practical Many of the Ring libraries (StdLib, WebLib, Natural Library, Games Engine, etc.) and the Ring IDE (Ring Notepad, Form Designer, etc.) are written in the Ring language itself. Ring is ready for use in production and increase the developers productivity. Check the Form Designer source code : https://github.com/ring-lang/ring/tree/master/tools/formdesigner We can run the Form Designer as Android application! 1.10. Practical 22
62.
Ring Documentation, Release1.16 Also we can run it in the Web Browser as a web application using WebAssembly 1.10. Practical 23
63.
CHAPTER TWO INTRODUCTION Welcome to theRing programming language! Ring is an Innovative and practical general-purpose multi-paradigm language that can be embedded in C/C++ projects, extended using C/C++ code and/or used as standalone language. The supported programming paradigms are Impera- tive, Procedural, Object-Oriented, Functional, Meta programming, Declarative programming using nested structures, and Natural programming. The language is portable (Windows, Linux, macOS, Android, etc.) and can be used to cre- ate Console, GUI, Web, Games and Mobile applications. The language is designed to be Simple, Small, Flexible and Fast. Its Dynamic Language that compile the source code to byte code then execute it by the Ring Virtual Machine, which is integrated with the Ring Compiler in one program. In this chapter we are going to discuss the goals behind the language design and implementation. 2.1 Motivation In Nov. 2011, I started to think about creating a new version of the Programming Without Coding Technology (PWCT) software from scratch. I was interested in creating multi-platform edition of the software beside adding support for Web & Mobile develop- ment. What I was looking for is a programming language that can be used to build the development environment, provides multi-platform support, more productivity, better performance, can be used for components scripting and developing different kinds of applications. Instead of using a mix of programming languages, I decided to use one programming language. I looked at many programming languages, but I discovered that I need a different language that comes with new ideas and intelligent implementation. 24
64.
Ring Documentation, Release1.16 2.2 Ring and other languages Ring is an innovative programming language that comes with better support for Natural Language Programming and Declarative Programming. The innovation comes in supporting these paradigms with new practical techniques on the top of Object-Oriented Programming and Functional Programming. Also Ring is influenced by the next programming languages • Lua • Python • Ruby • C • C# • BASIC • QML • xBase • Supernova 2.3 History In Sept. 2013 I started the design and the implementation of the Ring programming language. After 21 months of development, In May 2015 the language Compiler & Virtual Machine were ready for use! After that I spent three months testing the language again, trying to discover any bug to fix, writing better tests, by the end of August 2015, all know bugs were fixed, Writing many tests and testing automation helped a lot in getting a stable product. In September 12, 2015, most of the documentation was written. Before releasing the language I started the marketing by writing a post in Arabic language about it to my facebook profile page asking for contributors interested in the language idea after reading a short description, In the same day I got a lot of emails from developers and friends interested to contribute! Ring 1.0 is released on January 25, 2016 Ring 1.1 is released on October 6, 2016 Ring 1.2 is released on January 25, 2017 Ring 1.3 is released on May 15, 2017 Ring 1.4 is released on June 29, 2017 Ring 1.5 is released on August 21, 2017 Ring 1.6 is released on November 30, 2017 Ring 1.7 is released on January 25, 2018 Ring 1.8 is released on June 25, 2018 Ring 1.9 is released on October 6, 2018 Ring 1.10 is released on January 25, 2019 Ring 1.11 is released on September 15, 2019 2.2. Ring and other languages 25
65.
Ring Documentation, Release1.16 Ring 1.12 is released on January 25, 2020 Ring 1.13 is released on September 15, 2020 Ring 1.14 is released on January 25, 2021 Ring 1.15 is released on September 24, 2021 Ring 1.16 is released on October 23, 2021 2.4 Features The Ring language comes with the next features Tip: The language is ready for production! • Free Open Source (MIT License) • Hybrid Implementation (Compiler + Virtual Machine) • Declarative programming on the top of Object-Oriented programming • Natural Language Programming on the top of Object-Oriented programming • Natural Language Programming Library • Three different styles for writing the code and you can create your style • Syntax Flexibility (You can change the language keywords and operators) • The language keywords can be translated from English to other languages (Arabic, French, etc) • Compact Syntax, No explicit end for statements (No ; or ENTER is required) • Using braces { } we can access objects and use attributes/methods as variables/functions • Transparent Implementation (See the Tokens, Grammar, and Byte Code for each program) • Visual Implementation - Developed using Visual Programming (PWCT) • Written in ANSI C (The code is generated + Looks identical to Handwritten Code) • A small language – The compiler + The Virtual Machine (20,000 lines of C code) – The other 500,000 lines of code are related to libraries! • Portable (Windows, Linux, macOS, Android, etc) • Comments (One line & Multi-lines) • Not Case-Sensitive • Dynamic Typing • Weakly typed (Automatic conversion between numbers and strings only) • Lexical Scoping (Global, Local & Object State) • Default scope for variables inside functions (Local) • Default scope for variables outside functions (global) • We can have separate global scope for each library or sub project 2.4. Features 26
66.
Ring Documentation, Release1.16 • Garbage Collector - Automatic Memory Management (Escape Analysis and Reference Counting) • In most cases (90%) using Escape Analysis we don’t need to run the Garbage Collector (Faster) • Structure Programming • Rich control structures & Operators • For in get item by reference not value, you can read/edit the item • Use exit to go outside from more than one loop (Use it for programming in the small only) • Procedures/Functions • Main Function (Optional - To avoid using the Global Scope) • Call Function before the definition (Top-Down Programming) • Recursion • Multi-line literals • Access (read/write) string letter by index • The list index start by 1 • No keyword to end Functions/Classes/Packages • Range operator ex: 1:10 and “a”:”z” • First Class Variables, Lists, Objects and Functions • Store/Copy Lists/Objects by value (Deep Copy) • Pass Lists/Objects by reference • Native Object-Oriented Support – Encapsulation – Setter/Getter (optional) – private state (optional) – Instantiation – Polymorphism – Composition – Inheritance (Single Inheritance) – Operator Overloading – Packages • Reflection and Meta-programming • Clear program structure (Statements then functions then packages & classes) • Exception Handling • Eval() to execute code during run-time • 8-bit clean, work on binary data directly • I/O commands • Math functions • String functions 2.4. Features 27
67.
Ring Documentation, Release1.16 • List functions • File processing functions • Database support (ODBC, SQLite, MySQL & PostgreSQL) • Security Functions (OpenSSL) • Internet Functions (LibCurl) • Zip Functions • CGI Library (Written in Ring) – HTTP Get – HTTP Post – File upload – Cookies – URL Encode – HTML Templates – HTML Special Characters – HTML Generation using Functions – HTML Generation using Classes – CRUD Example (using MVC) – Users Example (Register, Login and Check) • Deploying web applications in the Cloud • Extension using C/C++ (Simple API) • Embedding the language in C/C++ programs • Embedding Ring in Ring • Comes with code generator (Written in Ring) to quickly wrap C/C++ Libraries – Used to Support Allegro by creating RingAllegro – Used to Support LibSDL by creating RingLibSDL – Used to Support Qt by creating RingQt • Create 2D Games for Desktop and Mobile (Using the Allegro Library) • RingLibSDL Extension • Comes with simple Game Engine for 2D Games • RingOpenGL Extension • RingFreeGLUT Extension • RingRayLib Extension • RingTilengine Extension • Create GUI Applications for Desktop and Mobile (Using the Qt Framework) • Comes with IDE contains the Code Editor (Ring Notepad) and the Form Designer • RingREPL (Read-Eval-Print-Loop) 2.4. Features 28
68.
Ring Documentation, Release1.16 • Tracing and Debugging • Type Hints Library • Comes with Ring2EXE to distribute applications • RingLibuv Extension • RingLibui Extension • RingSockets Extension • RingThreads Extension • No Global Interpreter (VM) lock (No GIL) - Better for threads and concurrency (Faster) • Comes with RingPM (Package Manager) • Many Samples and Applications • Complete Documentation. 2.5 License The Ring Programming Language http://ring-lang.net/ Version 1.16 The MIT License (MIT) Copyright (c) Mahmoud Fayed Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documen- tation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PAR- TICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFT- WARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2.5. License 29
69.
CHAPTER THREE USING RING NOTEPAD Inthis chapter we will learn about using Ring Notepad to write and execute Ring programs quickly Ring Notepad is just a simple application developed using the Ring language. 3.1 Ring Notepad - Main Window When we run the Ring Notepad we get the next dockable windows • Project Files Window : where we can select and open any ring file (*.ring) quickly. • Source Code Window : Where we write the source code. • Form Designer Window : The Form Designer to create GUI application forms. • Web Browser Window : Where we read the documentation or quickly open any website. • Output Window : Output when we run programs that print to the standard output • Function Window : List of functions in the current source file • Classes Window : List of classes in the current source file 30
70.
Ring Documentation, Release1.16 3.2 Creating and running your first Console Application At first we will type the source code see "Hello, World!" As in the next image Then we will click on the “Save” button from the toolbar (or press CTRL+S) Determine the source code file name and location. For example type : hello This will create a new source code file called : hello.ring 3.2. Creating and running your first Console Application 31
71.
Ring Documentation, Release1.16 To run the program click on “Debug (Run then wait!)” button from the toolbar The next screen shot present the application during the runtime Press Enter to continue and return to the Ring Notepad. 3.2. Creating and running your first Console Application 32
72.
Ring Documentation, Release1.16 3.3 Creating and running your first GUI/WebAssembly/Mobile Appli- cation To learn how to create GUI applications using Ring check the “Desktop, WebAssembly and Mobile development using RingQt” chapter. Source Code: load "guilib.ring" new qApp { new qWidget() { resize(400,400) setWindowTitle("Hello, World!") show() } exec() } In Ring notepad we have a special button to run GUI applications without displaying the console window. 3.3. Creating and running your first GUI/WebAssembly/Mobile Application 33
73.
Ring Documentation, Release1.16 The next screen shot present the application during the runtime 3.3. Creating and running your first GUI/WebAssembly/Mobile Application 34
74.
Ring Documentation, Release1.16 3.4 Creating and running your first Web Application To learn how to support Ring in your web server and how to create web applications check the “Web Development (CGI Library)” chapter. Note: You need to support the Ring language in your web server to be able to run the next example. Tip: For Windows users, Ring comes with Apache Web server! Using Ring Notepad we can run any web application from any folder directly without doing any configuration. Source Code: #!ring -cgi load "weblib.ring" import System.Web new Page { text("Hello, World!") } We can run the application in any web browser or in the browser that are embedded in Ring Notepad. We can run the web application using the Web icon. 3.4. Creating and running your first Web Application 35
75.
Ring Documentation, Release1.16 3.5 Creating and running your first Desktop/Mobile Game To learn about creating 2D Games using Ring check the “Demo Project - Game Engine for 2D Games” chapter. Source Code: load "gameengine.ring" func main oGame = New Game { title = "My First Game" sprite { type = GE_TYPE_PLAYER x=400 y=400 width=100 height=100 file = "images/player.png" transparent = true Animate=false Move=true Scaled=true } } We can run the application as any GUI application. 3.5. Creating and running your first Desktop/Mobile Game 36
76.
Ring Documentation, Release1.16 3.6 The Main File in the Project The idea of the Main File ToolBar is to determine the main file in the project When the project contains many source code files Using this feature we can run the project (Main File) at any time while opening other files in the project without the need to switch to the Main File to run the project. To quickly use this feature (Open the project main file) Press Ctrl+Shift+M to set the current source code file as the main file Open and modify other source code files in the project To run the project (Main File) at any time press Ctrl+Shift+F5 (GUI) or Ctrl+Shift+D (Console) Screen Shots: 3.6. The Main File in the Project 37
77.
Ring Documentation, Release1.16 3.7 The File Menu From this menu we can create, open and save the source code files. Another feature in this menu is “Print to PDF” 3.7. The File Menu 38
78.
Ring Documentation, Release1.16 3.8 The Edit Menu From the Edit menu we can Cut, Copy and Paste text. Also we can change the font and the colors. We can Go to a specific line or use the Find and Replace window to find and replace text. Also We can set the Tab Width (Number of Spaces) Starting from Ring 1.8 we have the (Find in Files) option. Starting from Ring 1.11 we have the (Insert Text, Lower Case, Upper Case & Capitalize) options. 3.8. The Edit Menu 39
79.
Ring Documentation, Release1.16 3.9 The View Menu From this menu we can show/hide the dockable windows Also we can change the Style of the Ring Notepad Common Styles are (Fusion White and Modern Black) Also we can quickly show/hide group of dockable windows based on the context 3.9. The View Menu 40
80.
Ring Documentation, Release1.16 3.10 The Program Menu From this menu we can run the programs Also we can set the Main file in the project 3.10. The Program Menu 41
81.
Ring Documentation, Release1.16 3.11 The Browser Menu From this menu we can quickly open common links in the browser 3.12 The Tools Menu From this menu we can run the Form Designer in separate window Also we can run the REPL (Read-Eval-Print-Loop) application 3.13 The Distribute Menu From this menu we can build an executable file for the application Also we can prepare the application for distribution 3.11. The Browser Menu 42
82.
Ring Documentation, Release1.16 3.14 The Help Menu From this menu we can get the help files (CHM & PDF) 3.14. The Help Menu 43
83.
CHAPTER FOUR GETTING STARTED -FIRST STYLE 4.1 Hello World The next program prints the Hello World message on the screen (std-out). see "Hello World" 4.2 Run the program to run the program, save the code in a file, for example : hello.ring then from the command line or terminal, run it using Ring ring hello.ring 4.3 Create Executable File Using Ring2EXE we can create executable file for our application ring2exe hello.ring -static 4.4 Not Case-Sensitive Since the Ring language is not case-sensitive, the same program can be written in different styles Tip: It’s better to select one style and use it in all of the program source code SEE "Hello World" See "Hello World" 44
84.
Ring Documentation, Release1.16 4.5 Multi-Line literals Using Ring we can write multi-line literal, see the next example See " Hello Welcome to the Ring programming language How are you? " Also you can use the nl variable to insert new line and you can use the + operator to concatenate strings As we have NL for new lines, we have Tab and CR (Carriage return) too! Note: nl value means a new line and the actual codes that represent a newline is different between operating systems See "Hello" + nl + "Welcome to the Ring programming language" + nl + "How are you?" 4.6 Getting Input You can get the input from the user using the give command See "What is your name? " Give cName See "Hello " + cName 4.7 No Explicit End For Statements You don’t need to use ‘;’ or press ENTER to separate statements. The previous program can be written in one line. See "What is your name? " give cName see "Hello " + cName 4.8 Using ? to print expression then new line It’s common to print new line after printing an expression, We can use the ? operator to do that! Example: ? "Hello, World!" for x = 1 to 10 ? x next Output: 4.5. Multi-Line literals 45
85.
Ring Documentation, Release1.16 Hello, World! 1 2 3 4 5 6 7 8 9 10 4.9 Writing Comments We can write one line comments and multi-line comments The comment starts with # or // Multi-lines comments are written between /* and */ /* Program Name : My first program using Ring Date : 2016.09.09 Author : Mahmoud Fayed */ See "What is your name? " # print message on screen give cName # get input from the user see "Hello " + cName # say hello! // See "Bye!" Note: Using // to comment a lines of code is just a code style. 4.9. Writing Comments 46
86.
CHAPTER FIVE GETTING STARTED -SECOND STYLE 5.1 Hello World The next program prints the Hello World message on the screen (std-out). put "Hello World" 5.2 Run the program to run the program, save the code in a file, for example : hello.ring then from the command line or terminal, run it using Ring ring hello.ring 5.3 Create Executable File Using Ring2EXE we can create executable file for our application ring2exe hello.ring -static 5.4 Not Case-Sensitive Since the Ring language is not case-sensitive, the same program can be written in different styles Tip: It’s better to select one style and use it in all of the program source code PUT "Hello World" Put "Hello World" 47
87.
Ring Documentation, Release1.16 5.5 Multi-Line literals Using Ring we can write multi-line literal, see the next example Put " Hello Welcome to the Ring programming language How are you? " Also you can use the nl variable to insert new line and you can use the + operator to concatenate strings As we have NL for new lines, we have Tab and CR (Carriage return) too! Note: nl value means a new line and the actual codes that represent a newline is different between operating systems Put "Hello" + nl + "Welcome to the Ring programming language" + nl + "How are you?" 5.6 Getting Input You can get the input from the user using the get command Put "What is your name? " Get cName Put "Hello " + cName 5.7 No Explicit End For Statements You don’t need to use ‘;’ or press ENTER to separate statements. The previous program can be written in one line. Put "What is your name? " get cName put "Hello " + cName 5.8 Writing Comments We can write one line comments and multi-line comments The comment starts with # or // Multi-lines comments are written between /* and */ /* Program Name : My first program using Ring Date : 2016.09.09 Author : Mahmoud Fayed */ (continues on next page) 5.5. Multi-Line literals 48
88.
Ring Documentation, Release1.16 (continued from previous page) Put "What is your name? " # print message on screen get cName # get input from the user put "Hello " + cName # say hello! // Put "Bye!" Note: Using // to comment a lines of code is just a code style. 5.8. Writing Comments 49
89.
CHAPTER SIX GETTING STARTED -THIRD STYLE 6.1 Hello World The next program prints the Hello World message on the screen (std-out). load "stdlib.ring" print("Hello World") 6.2 Run the program to run the program, save the code in a file, for example : hello.ring then from the command line or terminal, run it using Ring ring hello.ring 6.3 Create Executable File Using Ring2EXE we can create executable file for our application ring2exe hello.ring -static The -static option will avoid the need to ring.dll|ring.so|ring.dylib But since the stdlib.ring load libraries like (LibCurl, OpenSSL, MySQL, etc) You will need these libraries! To avoid the need to these libraries (If you don’t need stdlib classes) Use stdlibcore.ring instead of stdlib.ring as in the next example load "stdlibcore.ring" print("Hello World") Using stdlibcore.ring You can access the stdlib functions but not the stdlib classes. if you want to use stdlib.ring and distribute your application 50
90.
Ring Documentation, Release1.16 ring2exe hello.ring -dist -allruntime -noqt -noallegro 6.4 Not Case-Sensitive Since the Ring language is not case-sensitive, the same program can be written in different styles Tip: It’s better to select one style and use it in all of the program source code LOAD "stdlib.ring" PRINT("Hello World") Load "stdlib.ring" Print("Hello World") 6.5 Multi-Line literals Using Ring we can write multi-line literal, see the next example Load "stdlib.ring" Print(" Hello Welcome to the Ring programming language How are you? ") Also you can use the n to insert new line and you can use #{variable_name} to insert variables values. Load "stdlib.ring" Print( "HellonWelcome to the Ring programming languagenHow are you?") 6.6 Getting Input You can get the input from the user using the getstring() function Load "stdlib.ring" Print("What is your name? ") cName = GetString() Print("Hello #{cName}") 6.4. Not Case-Sensitive 51
91.
Ring Documentation, Release1.16 6.7 No Explicit End For Statements You don’t need to use ‘;’ or press ENTER to separate statements. The previous program can be written in one line. Load "stdlib.ring" Print("What is your name? ") cName=getstring() print("Hello #{cName}") 6.8 Writing Comments We can write one line comments and multi-line comments The comment starts with # or // Multi-lines comments are written between /* and */ /* Program Name : My first program using Ring Date : 2016.09.09 Author : Mahmoud Fayed */ Load "stdlib.ring" Print("What is your name? ") # print message on screen cName=GetString() # get input from the user print("Hello #{cName}") # say hello! // print("Bye!") Note: Using // to comment a lines of code is just a code style. 6.7. No Explicit End For Statements 52
92.
CHAPTER SEVEN VARIABLES To create anew variable, you just need to determine the variable name & value. The value will determine the variable type and you can change the value to switch between the types using the same variable name. Syntax: <Variable Name> = <Value> Tip: The operator ‘=’ is used here as an Assignment operator and the same operator can be used in conditions, but for testing equality of expressions. Note: The Variable will contains the real value (not a reference). This means that once you change the variable value, the old value will be removed from memory (even if the variable contains a list or object). 7.1 Dynamic Typing Ring is a dynamic programming language that uses Dynamic Typing. x = "Hello" # x is a string see x + nl x = 5 # x is a number (int) see x + nl x = 1.2 # x is a number (double) see x + nl x = [1,2,3,4] # x is a list see x # print list items x = date() # x is a string contains date see x + nl x = time() # x is a string contains time see x + nl x = true # x is a number (logical value = 1) see x + nl x = false # x is a number (logical value = 0) see x + nl 53
93.
Ring Documentation, Release1.16 7.2 Deep Copy We can use the assignment operator ‘=’ to copy variables. We can do that to copy values like strings & numbers. Also, we can copy complete lists & objects. The assignment operator will do a complete duplication for us. This operation called Deep Copy list = [1,2,3,"four","five"] list2 = list list = [] See list # print the first list - no items to print See "********" + nl See list2 # print the second list - contains 5 items 7.3 Implicit Conversion The language can automatically convert between numbers and strings. Rules: <NUMBER> + <STRING> --> <NUMBER> <STRING> + <NUMBER> --> <STRING> Note: The same operator ‘+’ can be used as an arithmetic operator or for string concatenation. Example: x = 10 # x is a number y = "20" # y is a string sum = x + y # sum is a number (y will be converted to a number) Msg = "Sum = " + sum # Msg is a string (sum will be converted to a string) see Msg + nl 7.2. Deep Copy 54
94.
CHAPTER EIGHT OPERATORS In this chapterwe will introduce the operators provided by the Ring programming language. 8.1 Arithmetic Operators The next table presents all of the arithmetic operators provided by the Ring language. Assume variable X=50 and variable Y=10 then: Operator Description Example Result + Add x+y 60 - Subtract x-y 40 * Multiplies x*y 500 / Divide x/y 5 % Modulus x%y 0 ++ Increment x++ 51 - - Decrement x- - 49 8.2 Relational Operators The next table presents all of the relational operators provided by the Ring language. Assume variable X=50 and variable Y=10 then: Operator Description Example Result = Equal x = y False != Not Equal x != y True > Greater than x > y True < Less than x < y False >= Greater or Equal x >= y True <= Less than or Equal x <= y False 55
95.
Ring Documentation, Release1.16 8.3 Logical Operators The next table presents all of the logical operators provided by the Ring language. Assume variable X=True and variable Y=False then: Operator Description Example Result and Logical AND x and y False or Logical OR x or y True not Logical Not not x False Another style Operator Description Example Result && Logical AND x && y False || Logical OR x || y True ! Logical Not ! x False 8.4 Bitwise Operators The next table presents all of the bitwise operators provided by the Ring language. Assume variable X=8 and variable Y=2 then: Operator Description Example Result & Binary AND x & y 0 | Binary OR x | y 10 ^ Binary XOR x ^ y 10 ~ Binary Ones Complement ~x -9 << Binary Left Shift x << y 32 >> Binary Right Shift x >> y 2 8.5 Assignment Operators The next table presents all of the assignment operators provided by the Ring language. Assume variable X=8 then: Operator Description Example Result = Assignment x = 10 x=10 += Add AND assignment x += 5 x=13 -= Subtract AND assignment x -= 3 x=5 *= Multiply AND assignment x *= 2 x=16 /= Divide AND assignment x /= 3 x=2.67 %= Modulus AND assignment x %= 2 x=0 <<= Left shift AND assignment x <<= 2 x=32 >>= Right shift AND assignment x >>= 2 x=2 &= Bitwise AND assignment x &= 4 x=0 |= Bitwise OR and assignment x |= 3 x=11 ^= Bitwise XOR and assignment x ^= 4 x=12 8.3. Logical Operators 56
96.
Ring Documentation, Release1.16 8.6 Misc Operators Operator Description :literal using : before identifier mean literal Start:End create list contains items from start to end [list items] define list items list[index] access list item obj.name using the dot operator to access object members (attributes/methods). obj {stmts} execute statements with direct access to object attributes & methods func(para,...) call function using parameters separated by comma ? <expr> Print expression then new line 8.7 Operators Precedence The next table present operators from higher precedence (Evaluated first) to lower precedence. Operator . [] () {} - ~ :Literal [list items] ++ - - Start:End * / % + - << >> & | ^ < > <= >= = != not ! and or && || Assignment = += -= *= /= %=>>= <<= &= ^= |= ? Example: See 3+5*4 # prints 23 8.6. Misc Operators 57
97.
CHAPTER NINE CONTROL STRUCTURES -FIRST STYLE In this chapter we are going to learn about the control structures provided by the Ring programming language. 9.1 Branching • If Statement Syntax: if Expression Block of statements but Expression Block of statements else Block of statements ok Example: see " Main Menu --------- (1) Say Hello (2) About (3) Exit " give nOption if nOption = 1 see "Enter your name : " give name see "Hello " + name + nl but nOption = 2 see "Sample : using if statement" + nl but nOption = 3 bye else see "bad option..." + nl ok • Switch Statement Syntax: switch Expression on Expression Block of statements other Block of statements off 58
98.
Ring Documentation, Release1.16 Example: See " Main Menu --------- (1) Say Hello (2) About (3) Exit " Give nOption Switch nOption On 1 See "Enter your name : " Give name See "Hello " + name + nl On 2 See "Sample : using switch statement" + nl On 3 Bye Other See "bad option..." + nl Off 9.2 Looping • While Loop Syntax: while Expression Block of statements end Example: While True See " Main Menu --------- (1) Say Hello (2) About (3) Exit " Give nOption Switch nOption On 1 See "Enter your name : " Give name See "Hello " + name + nl On 2 See "Sample : using while loop" + nl On 3 Bye Other See "bad option..." + nl Off End • For Loop 9.2. Looping 59
99.
Ring Documentation, Release1.16 Syntax: for identifier=expression to expression [step expression] Block of statements next Example: # print numbers from 1 to 10 for x = 1 to 10 see x + nl next Example: # Dynamic loop See "Start : " give nStart See "End : " give nEnd See "Step : " give nStep For x = nStart to nEnd Step nStep see x + nl Next Example: # print even numbers from 0 to 10 for x = 0 to 10 step 2 see x + nl next Example: # print even numbers from 10 to 0 for x = 10 to 0 step -2 see x + nl next • For in Loop Syntax: for identifier in List/String [step expression] Block of statements next Example: aList = 1:10 # create list contains numbers from 1 to 10 for x in aList see x + nl next # print numbers from 1 to 10 9.2. Looping 60
100.
Ring Documentation, Release1.16 9.3 Using The Step option with For in We can use the Step option with For in to skip number of items in each iteration Example: aList = 1:10 # create list contains numbers from 1 to 10 # print odd items inside the list for x in aList step 2 see x + nl next 9.4 Using For in to modify lists When we use (For in) we get items by reference. This means that we can read/edit items inside the loop. Example: aList = 1:5 # create list contains numbers from 1 to 5 # replace list numbers with strings for x in aList switch x on 1 x = "one" on 2 x = "two" on 3 x = "three" on 4 x = "four" on 5 x = "five" off next see aList # print the list items 9.5 Do Again Loop Syntax: do Block of statements again expression Example: x = 1 do see x + nl x++ again x <= 10 9.3. Using The Step option with For in 61
101.
Ring Documentation, Release1.16 9.6 Exit Command Used to go outside one or more of loops. Syntax: exit [expression] # inside loop Example: for x = 1 to 10 see x + nl if x = 5 exit ok next 9.7 Exit from two loops The next example presents how to use the exit command to exit from two loops in one jump. Example: for x = 1 to 10 for y = 1 to 10 see "x=" + x + " y=" + y + nl if x = 3 and y = 5 exit 2 # exit from 2 loops ok next next 9.8 Loop Command Used to jump to the next iteration in the loop. Syntax: loop [expression] # inside loop Example: for x = 1 to 10 if x = 3 see "Number Three" + nl loop ok see x + nl next 9.6. Exit Command 62
102.
Ring Documentation, Release1.16 9.9 Short-circuit evaluation The logical operators and/or follow the short-circuit evaluation. If the first argument of the AND operator is zero, then there is no need to evaluate the second argument and the result will be zero. If the first argument of the OR operator is one, then there is no need to evaluate the second argument and the result will be one. Example: /* output ** nice ** nice ** great */ x = 0 y = 10 if (x = 0 and nice()) and (y = 10 and nice()) see "great" + nl ok func nice see "nice" + nl return 1 Example: # No output x = 0 y = 10 if (x = 1 and nice()) and (y = 10 and nice()) see "great" + nl ok func nice see "nice" + nl return 1 Example: /* output ** nice ** great */ x = 0 y = 10 if (x = 0 and nice()) or (y = 10 and nice()) see "great" + nl ok func nice see "nice" + nl return 1 9.9. Short-circuit evaluation 63
103.
Ring Documentation, Release1.16 9.10 Comments about evaluation • True, False, nl & NULL are variables defined by the language • True = 1 • False = 0 • nl = new line • NULL = empty string = “” • Everything evaluates to true except 0 (False). Example: # output = message from the if statement if 5 # 5 evaluates to true because it's not zero (0). see "message from the if statement" + nl ok 9.10. Comments about evaluation 64
104.
CHAPTER TEN CONTROL STRUCTURES -SECOND STYLE In this chapter we are going to learn about the second style of control structures provided by the Ring programming language. 10.1 Branching • If Statement Syntax: if Expression Block of statements elseif Expression Block of statements else Block of statements end Example: put " Main Menu --------- (1) Say Hello (2) About (3) Exit " get nOption if nOption = 1 put "Enter your name : " get name put "Hello " + name + nl elseif nOption = 2 put "Sample : using if statement" + nl elseif nOption = 3 bye else put "bad option..." + nl end • Switch Statement Syntax: switch Expression case Expression Block of statements else (continues on next page) 65
105.
Ring Documentation, Release1.16 (continued from previous page) Block of statements end Example: Put " Main Menu --------- (1) Say Hello (2) About (3) Exit " Get nOption Switch nOption Case 1 Put "Enter your name : " Get name Put "Hello " + name + nl Case 2 Put "Sample : using switch statement" + nl Case 3 Bye Else Put "bad option..." + nl End 10.2 Looping • While Loop Syntax: while Expression Block of statements end Example: While True Put " Main Menu --------- (1) Say Hello (2) About (3) Exit " Get nOption Switch nOption Case 1 Put "Enter your name : " Get name Put "Hello " + name + nl Case 2 Put "Sample : using while loop" + nl Case 3 Bye Else (continues on next page) 10.2. Looping 66
106.
Ring Documentation, Release1.16 (continued from previous page) Put "bad option..." + nl End End • For Loop Syntax: for identifier=expression to expression [step expression] Block of statements end Example: # print numbers from 1 to 10 for x = 1 to 10 put x + nl end Example: # Dynamic loop Put "Start : " get nStart Put "End : " get nEnd Put "Step : " get nStep For x = nStart to nEnd Step nStep Put x + nl End Example: # print even numbers from 0 to 10 for x = 0 to 10 step 2 Put x + nl end Example: # print even numbers from 10 to 0 for x = 10 to 0 step -2 put x + nl end • For in Loop Syntax: for identifier in List/String [step expression] Block of statements end Example: aList = 1:10 # create list contains numbers from 1 to 10 for x in aList put x + nl end # print numbers from 1 to 10 10.2. Looping 67
107.
Ring Documentation, Release1.16 10.3 Exceptions try Block of statements catch Block of statements end 10.3. Exceptions 68
108.
CHAPTER ELEVEN CONTROL STRUCTURES -THIRD STYLE In this chapter we are going to learn about the third style of control structures provided by the Ring programming language. 11.1 Branching • If Statement Syntax: if Expression { Block of statements elseif Expression Block of statements else Block of statements } Example: Load "stdlib.ring" print(" Main Menu --------- (1) Say Hello (2) About (3) Exit ") nOption = getnumber() if nOption = 1 { print("Enter your name : ") name = getstring() print("Hello #{name}n") elseif nOption = 2 print("Sample : using if statementn") elseif nOption = 3 bye else print("bad option...n") } 69
109.
Ring Documentation, Release1.16 • Switch Statement Syntax: switch Expression { case Expression Block of statements else Block of statements } Example: Load "stdlib.ring" print(" Main Menu --------- (1) Say Hello (2) About (3) Exit ") nOption = GetString() switch nOption { case 1 print("Enter your name : ") name = getstring() print("Hello #{name}n") case 2 print("Sample : using switch statementn") case 3 Bye else print("bad option...n") } 11.2 Looping • While Loop Syntax: while Expression { Block of statements } Example: Load "stdlib.ring" While True { print(" (continues on next page) 11.2. Looping 70
110.
Ring Documentation, Release1.16 (continued from previous page) Main Menu --------- (1) Say Hello (2) About (3) Exit ") nOption = GetString() switch nOption { case 1 print("Enter your name : ") name = getstring() print("Hello #{name}n") case 2 print("Sample : using switch statementn") case 3 Bye else print("bad option...n") } } • For Loop Syntax: for identifier=expression to expression [step expression] { Block of statements } Example: # print numbers from 1 to 10 load "stdlib.ring" for x = 1 to 10 { print("#{x}n") } Example: load "stdlib.ring" # Dynamic loop print("Start : ") nStart = getnumber() print("End : ") nEnd = getnumber() print("Step : ") nStep = getnumber() for x = nStart to nEnd step nStep { print("#{x}n") } Example: load "stdlib.ring" (continues on next page) 11.2. Looping 71
111.
Ring Documentation, Release1.16 (continued from previous page) # print even numbers from 0 to 10 for x = 0 to 10 step 2 { print("#{x}n") } Example: load "stdlib.ring" # print even numbers from 10 to 0 for x = 10 to 0 step -2 { print("#{x}n") } • For in Loop Syntax: for identifier in List/String [step expression] { Block of statements } Example: load "stdlib.ring" aList = 1:10 # create list contains numbers from 1 to 10 for x in aList { print("#{x}n") } # print numbers from 1 to 10 Example: load "stdlib.ring" aList = 1:10 # create list contains numbers from 1 to 10 # print odd items inside the list for x in aList step 2 { print("#{x}n") } When we use (For in) we get items by reference. This means that we can read/edit items inside the loop. Example: load "stdlib.ring" aList = 1:5 # create list contains numbers from 1 to 5 # replace list numbers with strings for x in aList { switch x { case 1 x = "one" case 2 x = "two" case 3 x = "three" case 4 x = "four" case 5 x = "five" } (continues on next page) 11.2. Looping 72
112.
Ring Documentation, Release1.16 (continued from previous page) } print(aList) # print the list items 11.3 Exceptions try { Block of statements catch Block of statements } 11.3. Exceptions 73
113.
CHAPTER TWELVE GETTING INPUT We canget input from the keyboard using • The Give Command • The GetChar() Function • The Input() Function 12.1 Give Command Syntax: Give VariableName Example: See "Enter the first number : " Give nNum1 See "Enter the second number : " Give nNum2 See "Sum : " + ( 0 + nNum1 + nNum2 ) Output: Enter the first number : 3 Enter the second number : 4 Sum : 7 12.2 GetChar() Function We can get one character from the standard input using the GetChar() function Syntax: GetChar() ---> Character Example: While True See " Main Menu (1) Say Hello (continues on next page) 74
114.
Ring Documentation, Release1.16 (continued from previous page) (2) Exit " Option = GetChar() GetChar() GetChar() # End of line # the previous two lines can be replaced with the next line # Give Option if Option = 1 see "Enter your name : " give cName see "Hello " + cName else bye ok End 12.3 Input() Function We can get input from the keyboard using the Input() function Syntax: Input(nCount) ---> string The function will wait until nCount characters (at least) are read Example: See "Enter message (30 characters) : " cMsg = input(30) See "Message : " + cMsg 12.3. Input() Function 75
115.
CHAPTER THIRTEEN FUNCTIONS - FIRSTSTYLE In this chapter we are going to learn about the next topics :- • Define functions • Call functions • Declare parameters • Send parameters • Main Function • Variables Scope • Return Value • Recursion 13.1 Define Functions To define new function Syntax: func <function_name> [parameters] Block of statements Note: No keyword is required to end the function definition. Example: func hello see "Hello from function" + nl 76
116.
Ring Documentation, Release1.16 13.2 Call Functions To call function without parameters, we type the function name then () Tip: We can call the function before the function definition and the function code. Example: hello() func hello see "Hello from function" + nl Example: first() second() func first see "message from the first function" + nl func second see "message from the second function" + nl 13.3 Declare parameters To declare the function parameters, after the function name type the list of parameters as a group of identifiers separated by comma. Example: func sum x,y see x+y+nl 13.4 Send Parameters To send parameters to function, type the parameters inside () after the function name Syntax: funcname(parameters) Example: /* output ** 8 ** 3000 */ sum(3,5) sum(1000,2000) func sum x,y see x+y+nl 13.2. Call Functions 77
117.
Ring Documentation, Release1.16 13.5 Main Function Using the Ring programming language, the Main Function is optional, when it’s defined, it will be executed after the end of other statements. if no other statements comes alone, the main function will be the first entry point Example: # this program will print the hello world message first then execute the main function See "Hello World!" + nl func main see "Message from the main function" + nl 13.6 Variables Scope The Ring programming language uses lexical scoping to determine the scope of a variable. Variables defined inside functions (including function parameters) are local variables. Variables defined outside func- tions (before any function) are global variables. Inside any function we can access the variables defined inside this function beside the global variables. Example: # the program will print numbers from 10 to 1 x = 10 # x is a global variable. func main for t = 1 to 10 # t is a local variable mycounter() # call function next func mycounter see x + nl # print the global variable value x-- # decrement Note: Using the main function before the for loop declare the t variable as a local variable, It’s recommended to use the main functions instead of typing the instructions directly to set the scope of the new variables to local. 13.5. Main Function 78
118.
Ring Documentation, Release1.16 13.7 Return Value The function can return a value using the Return command. Syntax: Return [Expression] Tip: the Expression after the return command is optional and we can use the return command to end the function execution without returning any value. Note: if the function doesn’t return explicit value, it will return NULL (empty string = “” ). Example: if novalue() = NULL See "the function doesn't return a value" + nl ok func novalue 13.8 Recursion The Ring programming language support Recursion and the function can call itself using different parameters. Example: see fact(5) # output = 120 func fact x if x = 0 return 1 else return x * fact(x-1) ok 13.7. Return Value 79
119.
CHAPTER FOURTEEN FUNCTIONS - SECONDSTYLE In this chapter we are going to learn about the next topics :- • Define functions • Call functions • Declare parameters • Send parameters • Main Function • Variables Scope • Return Value • Recursion 14.1 Define Functions To define new function Syntax: def <function_name> [parameters] Block of statements [end] Note: the keyword ‘end’ is optional. Example: def hello put "Hello from function" + nl end 80
120.
Ring Documentation, Release1.16 14.2 Call Functions To call function without parameters, we type the function name then () Tip: We can call the function before the function definition and the function code. Example: hello() def hello put "Hello from function" + nl end Example: first() second() def first put "message from the first function" + nl def second put "message from the second function" + nl 14.3 Declare parameters To declare the function parameters, after the function name type the list of parameters as a group of identifiers separated by comma. Example: def sum x,y put x+y+nl end 14.4 Send Parameters To send parameters to function, type the parameters inside () after the function name Syntax: funcname(parameters) Example: /* output ** 8 ** 3000 */ sum(3,5) sum(1000,2000) def sum x,y put x+y+nl 14.2. Call Functions 81
121.
Ring Documentation, Release1.16 14.5 Main Function Using the Ring programming language, the Main Function is optional, when it’s defined, it will be executed after the end of other statements. if no other statements comes alone, the main function will be the first entry point Example: # this program will print the hello world message first then execute the main function put "Hello World!" + nl def main put "Message from the main function" + nl end 14.6 Variables Scope The Ring programming language uses lexical scoping to determine the scope of a variable. Variables defined inside functions (including function parameters) are local variables. Variables defined outside func- tions (before any function) are global variables. Inside any function we can access the variables defined inside this function beside the global variables. Example: # the program will print numbers from 10 to 1 x = 10 # x is a global variable. def main for t = 1 to 10 # t is a local variable mycounter() # call function end end def mycounter put x + nl # print the global variable value x-- # decrement end Note: Using the main function before the for loop declare the t variable as a local variable, It’s recommended to use the main functions instead of typing the instructions directly to set the scope of the new variables to local. 14.5. Main Function 82
122.
Ring Documentation, Release1.16 14.7 Return Value The function can return a value using the Return command. Syntax: Return [Expression] Tip: the Expression after the return command is optional and we can use the return command to end the function execution without returning any value. Note: if the function doesn’t return explicit value, it will return NULL (empty string = “” ). Example: if novalue() = NULL put "the function doesn't return a value" + nl end def novalue 14.8 Recursion The Ring programming language support Recursion and the function can call itself using different parameters. Example: put fact(5) # output = 120 def fact x if x = 0 return 1 else return x * fact(x-1) end 14.7. Return Value 83
123.
CHAPTER FIFTEEN FUNCTIONS - THIRDSTYLE In this chapter we are going to learn about the next topics :- • Define functions • Call functions • Declare parameters • Send parameters • Main Function • Variables Scope • Return Value • Recursion 15.1 Define Functions To define new function Syntax: func <function_name> [parameters] ['{'] Block of statements ['}'] Example: load "stdlib.ring" func hello { print("Hello from function n") } 84
124.
Ring Documentation, Release1.16 15.2 Call Functions To call function without parameters, we type the function name then () Tip: We can call the function before the function definition and the function code. Example: load "stdlib.ring" hello() func hello { print("Hello from function n") } Example: load "stdlib.ring" first() second() func first { print("message from the first function n") } func second { print("message from the second function n") } 15.3 Declare parameters To declare the function parameters, after the function name type the list of parameters as a group of identifiers separated by comma. Example: load "stdlib.ring" func sum(x,y) { print(x+y) } 15.4 Send Parameters To send parameters to function, type the parameters inside () after the function name Syntax: funcname(parameters) Example: 15.2. Call Functions 85
125.
Ring Documentation, Release1.16 /* output ** 8 ** 3000 */ load "stdlib.ring" sum(3,5) sum(1000,2000) func sum(x,y) { print(x+y) } 15.5 Main Function Using the Ring programming language, the Main Function is optional, when it’s defined, it will be executed after the end of other statements. if no other statements comes alone, the main function will be the first entry point Example: # this program will print the hello world message first then execute the main function load "stdlib.ring" print("Hello, World! n") func main { print("Message from the main function n") } 15.6 Variables Scope The Ring programming language uses lexical scoping to determine the scope of a variable. Variables defined inside functions (including function parameters) are local variables. Variables defined outside func- tions (before any function) are global variables. Inside any function we can access the variables defined inside this function beside the global variables. Example: # the program will print numbers from 10 to 1 load "stdlib.ring" x = 10 # x is a global variable. func main { for t = 1 to 10 { # t is a local variable mycounter() # call function } } func mycounter { (continues on next page) 15.5. Main Function 86
126.
Ring Documentation, Release1.16 (continued from previous page) print("#{x}n") # print the global variable value x-- # decrement } Note: Using the main function before the for loop declare the t variable as a local variable, It’s recommended to use the main functions instead of typing the instructions directly to set the scope of the new variables to local. 15.7 Return Value The function can return a value using the Return command. Syntax: Return [Expression] Tip: the Expression after the return command is optional and we can use the return command to end the function execution without returning any value. Note: if the function doesn’t return explicit value, it will return NULL (empty string = “” ). Example: load "stdlib.ring" if novalue() = NULL { print("the function doesn't return a valuen") } func novalue { } 15.8 Recursion The Ring programming language support Recursion and the function can call itself using different parameters. Example: load "stdlib.ring" print( fact(5) ) # output = 120 func fact(x) { if x = 0 { return 1 else return x * fact(x-1) } } 15.7. Return Value 87
127.
CHAPTER SIXTEEN PROGRAM STRUCTURE In thischapter we will learn about using many source code files in the same project. 16.1 Source Code File Sections Each source code file may contains the next sections (in the same order). Source Code File Sections Load Files Statements and Global Variables Functions Packages and Classes The application maybe one or more of files. 16.2 Using Many Source Code Files To include another source file in the project, just use the load command. Syntax: Load "filename.ring" Note: The Load command is executed directly by the compiler in the parsing stage Tip: if you don’t know the file name until the runtime, or you need to use functions to get the file path, just use eval(). Example: # File : Start.ring Load "sub.ring" sayhello("Mahmoud") 88
128.
Ring Documentation, Release1.16 # File : sub.ring func sayhello cName see "Hello " + cName + nl 16.3 Load Package Using the ‘load’ command we can use many ring source files in the same project But all of these files will share the same global scope We have also the “Load Package” command Using “Load Package” we can load a library (*.ring file) in new global scope This is very useful to create libraries that avoid conflicts in global variables Example: File: loadpackage.ring x = 100 ? "Hello, World!" load package "testloadpackage.ring" ? x test() File: testloadpackage.ring ? "Hello from testloadpackage.ring" x = 1000 test() func test ? x Output: Hello, World! Hello from testloadpackage.ring 1000 100 1000 16.3. Load Package 89
129.
Ring Documentation, Release1.16 16.4 Load Again Ring 1.12 comes with the Load Again command Using this command we can load the Ring source file which contains constants more than one time. This is useful when using Ring source files for translations through global constants. Example: The next function is part from a project which support Arabic and English languages The files english.ring and arabic.ring contains constants for translation One of these files is loaded in the start of the program Loading the same file again using the (Load) command is not possible Because the (Load) command load the same source file only for the first time and ignore next times. So we have to use the (Load Again) command. Where we can use these files again during the runtime as in the next code func setLang nLanguage if C_ENV_DEFAULT_LANG = nLanguage return ok C_ENV_DEFAULT_LANG = nLanguage # Change the language switch nLanguage on C_TRANSLATION_ENGLISH load again "translation/english.ring" on C_TRANSLATION_ARABIC load again "translation/arabic.ring" off 16.4. Load Again 90
130.
CHAPTER SEVENTEEN LISTS In this chapterwe are going to learn how to deal with lists. 17.1 Create Lists We can create new lists by defining the list items inside square brackets. Example: aList = [1,2,3,4,5] Also we can create new lists using the : operator Example: aList = 1:5 aList2 = "a":"z" Example: aList = 5:1 aList2 = "z":"a" Also we can create lists using the list() function Syntax: list = list(size) To create 2D list list = list(nRows,nCols) Example (1) aList = list(10) # aList contains 10 items Example (2) aList = list(5,4) # Create 2D List contains 5 rows and 4 columns Note: the list index start from 1 91
131.
Ring Documentation, Release1.16 17.2 Add Items To add new items to the list, we can use the Add() function. Syntax: Add(List,Item) Example: aList = ["one","two"] add(aList,"three") see aList Also we can do that using the + operator. Syntax: List + item Example: aList = 1:10 # create list contains numbers from 1 to 10 aList + 11 # add number 11 to the list see aList # print the list 17.3 Get List Size We can get the list size using the len() function Syntax: Len(List) Example: aList = 1:20 see len(aList) # print 20 17.4 Delete Item From List To delete an item from the list, we can use the del() function Syntax: del(list,index) Example: aList = ["one","two","other","three"] Del(aList,3) # delete item number three see aList # print one two three 17.2. Add Items 92
132.
Ring Documentation, Release1.16 17.5 Get List Item To get an item from the list, we uses the next syntax List[Index] Example: aList = ["Cairo","Riyadh"] see "Egypt : " + aList[1] + nl + "KSA : " + aList[2] + nl 17.6 Set List Item To set the value of an item inside the list, we can use the next syntax List[Index] = Expression Example: aList = list(3) # create list contains three items aList[1] = "one" aList[2] = "two" aList[3] = "three" see aList 17.7 Search To find an item inside the list we can use the find() function Syntax: Find(List,ItemValue) ---> Item Index Find(List,ItemValue,nColumn) ---> Search in nColumn, returns the Item Index Find(List,ItemValue,nColumn,cAttribute) ---> Item Index Example: aList = ["one","two","three","four","five"] see find(aList,"three") # print 3 Example: mylist = [["one",1], ["two",2], ["three",3]] see find(mylist,"two",1) + nl # print 2 see find(mylist,2,2) + nl # print 2 Also we can use the binarysearch() function to search in sorted list. Syntax: 17.5. Get List Item 93
133.
Ring Documentation, Release1.16 BinarySearch(List,ItemValue) ---> Item Index BinarySearch(List,ItemValue,nColumn) ---> Search in nColumn, returns the Item Index Example: aList = ["one","two","three","four","five"] aList = sort(aList) see binarysearch(aList,"three") Output: five four one three two 4 17.8 Sort We can sort the list using the sort() function. Syntax: Sort(List) ---> Sorted List Sort(List,nColumn) ---> Sorted List based on nColumn Sort(List,nColumn,cAttribute) ---> Sorted List based on Object Attribute Example: aList = [10,12,3,5,31,15] aList = sort(aList) see aList # print 3 5 10 12 15 31 We can sort list of strings Example: mylist = ["mahmoud","samir","ahmed","ibrahim","mohammed"] see mylist # print list before sorting mylist = sort(mylist) # sort list see "list after sort"+nl see mylist # print ahmed ibrahim mahmoud mohammed samir We can sort a list based on a specific column. Example: aList = [ ["mahmoud",15000] , ["ahmed", 14000 ] , ["samir", 16000 ] , ["mohammed", 12000 ] , ["ibrahim",11000 ] ] aList2 = sort(aList,1) see aList2 17.8. Sort 94
134.
Ring Documentation, Release1.16 Output: ahmed 14000 ibrahim 11000 mahmoud 15000 mohammed 12000 samir 16000 17.9 Reverse We can reverse a list using the reverse() function. Syntax: Reverse(List) ---> Reversed List Example: aList = [10,20,30,40,50] aList = reverse(aList) see aList # print 50 40 30 20 10 17.10 Insert Items To insert an item in the list we can use the insert() function. Syntax: Insert(List,Index,Item) The inserted item will be AFTER the Index Example: aList = ["A","B","D","E"] insert(aList,2,"C") # Inserts AFTER Index 2, "C" into Position 3 see aList # print A B C D E 17.9. Reverse 95
135.
Ring Documentation, Release1.16 17.11 Nested Lists The list may contain other lists Example: aList = [ 1 , [10,20,30] , 5 , [100,1000,5000] ] aList2 = [ "one","two", [3,4], [20,30], ["three", "four", "five",[100,200,300] ] ] see aList[2] # print 10 20 30 see aList[4][3] + nl # print 5000 see aList2[5][2] + nl # print four see aList2[5][4][3] # print 300 17.12 Copy Lists We can copy lists (including nested lists) using the Assignment operator. Example: aList = [ "one","two", [3,4], [20,30], ["three", "four", "five",[100,200,300] ] ] aList2 = aList # Copy aList to aList2 aList2[5] = "other" # modify item number five see aList2[5] + nl # print other see aList[5] # print three four five 100 200 300 17.13 First-class lists Lists are first-class citizens where we can store lists in variables, pass lists to functions, and return lists from functions. Example: aList = duplicate( [1,2,3,4,5] ) see aList[10] + nl # print 5 see mylist() # print 10 20 30 40 50 func duplicate list (continues on next page) 17.11. Nested Lists 96
136.
Ring Documentation, Release1.16 (continued from previous page) nMax = len(list) for x = 1 to nMax list + list[x] next return list func mylist return [10,20,30,40,50] 17.14 Using Lists during definition We can use the list and the list items while we are defining the list for the first time. Example: aList = [ [1,2,3,4,5] , aList[1] , aList[1] ] see aList # print 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 Example: x = [ 1, 2, x ] ? x # print 1 2 1 2 ? len(x) # print 3 ? x[1] # print 1 ? x[2] # print 2 ? x[3] # print 1 2 Output: 1 2 1 2 3 1 2 1 2 17.15 Passing Lists to Functions Lists are passed to functions by reference, This means that the called function will work on the same list and can modify it. Example: func main aList = [1,2,3,4,5] # create list, local in function main myfunc(aList) # call function, pass list by reference see aList # print 1 2 3 4 5 6 7 8 9 10 func myfunc list list + [6,7,8,9,10] 17.14. Using Lists during definition 97
137.
Ring Documentation, Release1.16 17.16 Access List Items by String Index Instead of using numbers to determine the item index when we get item value or set item value, We can access items using string index if the item is a list contains two items and the first item is a string. Example: aList = [ ["one",1] , ["two",2] , ["three",3] ] see aList["one"] + nl + aList["two"] + nl + aList["three"] # print 1 2 3 This type of lists can be defined in a better syntax using the : and = operators. Example: aList = [ :one = 1 , :two = 2 , :three = 3 ] see aList["one"] + nl + aList["two"] + nl + aList["three"] + nl # print 1 2 3 see aList[1] # print one 1 Tip: using : before identifier (one word) means literal Note: using = inside list definition create a list of two items where the first item is the left side and the second item is the right side. We can add new items to the list using the string index Example: aList = [] aList["Egypt"] = "Cairo" aList["KSA"] = "Riyadh" see aList["Egypt"] + nl + # print Cairo aList["KSA"] + nl # print Riyadh 17.17 Passing Parameters or Arguments Using List This type of lists is very good for passing parameters to functions Where the order of parameters will not be important (we can change the order). Also some parameters maybe optional. Example: myconnect ( [ :server = "myserver.com" , :port = 80 , :username = "mahmoud" , :password = "password" ] ) func myconnect mypara # print connection details (continues on next page) 17.16. Access List Items by String Index 98
138.
Ring Documentation, Release1.16 (continued from previous page) see "User Name : " + mypara[:username] + nl + "Password : " + mypara[:password] + nl + "Server : " + mypara[:server] + nl + "Port : " + mypara[:port] 17.18 Passing Parameters or Arguments Using List Array Passing Arguments or Parameters to a Function in an array format Example: myList = [5,7,3,9] ### list with args or parms in an array result = sum(myList) See "Sum result: "+ result +n func sum(aList) acc = 0 sizeList = len(aList) for i = 1 to sizeList See aList[i] +nl acc = acc + aList[i] next return acc 17.19 Return Parameters as List or Hash Table Return Parameters from a Function in an Array or Hash Format Example: sudoku = [ [2,9,0], [0,0,1], [0,0,0] ] aOutput = myFunctionArray(sudoku) See "Return Array: T/F: "+ aOutput[1] +" Row: "+ aOutput[2] +" Col: "+ ˓ →aOutput[3] +nl aOutput = myFunctionHash(sudoku) See "Return Hash.: T/F: "+ aOutput[:lValue] +" Row: "+ aOutput[:nRow] +" Col: ˓ →"+ aOutput[:nCol] +nl ###---------------------------------- ### isSolvedSoduku - Return ARRAY Func myFunctionArray(sudoku) for Row = 1 to 9 for Col = 1 to 9 if sudoku[Row][Col] = 0 //---------------------------- (continues on next page) 17.18. Passing Parameters or Arguments Using List Array 99
139.
Ring Documentation, Release1.16 (continued from previous page) // Return Array with 3 fields return [False, Row, Col] ok next next return [True, Row, Col] ###---------------------------------- ### isSolvedSoduku - Return HASH Func myFunctionHash(sudoku) for Row = 1 to 3 for Col = 1 to 3 if sudoku[Row][Col] = 0 //--------------------------------- // Return Hash Table with 3 fields return [ :lValue = False, :nRow = Row, :nCol = Col ] ok next next return [ :lValue = False, :nRow = Row, :nCol = Col ] ###----------------------------- 17.20 Creating a Multi-Dimensional Array using List A Multi-Dimensional Array of any size can be built using recursion in a Function Example: ###--------------------------------------------------------- ### Create Array -- Dimensions Any Size: 3D, 4D, 5D etc dimList = [4,3,4] bList = createDimList(dimList) ###--------------------------------------------------------- ### Populate the arrays using a counter 1 , 4x4x4 = 256 , 2x3x4x5x6 = 720 Counter = 1 for Col=1 to dimList[1] for Row=1 to dimList[2] for Dep=1 to dimList[3] blist[Col][Row][Dep] = Counter Counter++ next next next (continues on next page) 17.20. Creating a Multi-Dimensional Array using List 100
140.
Ring Documentation, Release1.16 (continued from previous page) ###----------------------------------------------- ### Print the array elements in block format for Col=1 to dimList[1] for Row=1 to dimList[2] for Dep=1 to dimList[3] See bList[Col][Row][Dep] See " " next See nl next See nl next ###=========================== ### FUNCTIONS ###----------------------------------------------------------------------- ### Recursive Create a Dimension Array ### Call by passing an array of dimensions: dimList = [2,3,4,5] ### Drop the first entry every iteration call, making newParms ### ### Example: ### dimList = [4,2,3,2] <<< Number and size of dimensions in array ˓ →format ### bList = createDimList(dimList) <<< Call using the array as input func createDimList(dimArray) sizeList = len(dimArray) newParms = [] for i = 2 to sizeList Add(newParms, dimArray[i]) next alist = list(dimArray[1]) if sizeList = 1 return aList ok for t in alist t = createDimList(newParms) next return alist 17.20. Creating a Multi-Dimensional Array using List 101
141.
Ring Documentation, Release1.16 17.21 Swap Items We can swap the list items using the Swap() function. Example: aList = [:one,:two,:four,:three] see aList see copy("*",50) + nl swap(aList,3,4) see aList Output one two four three ************************************************** one two three four 17.21. Swap Items 102
142.
CHAPTER EIGHTEEN STRINGS In this chapterwe are going to learn about strings creation and manipulation. 18.1 String Literals Syntax: cStr = "This is a string" cStr2 = 'Another string' cStr3 = :JustAnotherString cStr4 = `Yet "another" 'string' ! ` 18.2 Get String Length We can get the string length (letters count inside a string) using the len() function Syntax: len(string) ---> string length Example: cStr = "How are you?" see cStr + nl see "String size : " + len(cStr) + nl 18.3 Convert Letters Case Syntax: lower(string) ---> convert string letters to lower case upper(string) ---> convert string letters to UPPER case Example: cStr = "Welcome To The Ring Programming Language" see cStr + nl + upper(cStr) + nl + lower(cStr) 103
143.
Ring Documentation, Release1.16 18.4 Access String Letters We can access a letter inside a string by the letter index Syntax: string[index] ---> get string letter string[index] = letter # set string letter Example: # print user name letter by letter (each letter in new line) See "Hello, Enter your name : " give cName for x = 1 to len(cName) see nl + cName[x] next We can use for in to get string letters. Example: # print user name letter by letter (each letter in new line) See "Hello, Enter your name : " give cName for x in cName see nl + x next We can modify the string letters Example: # convert the first letter to UPPER case See "Enter your name : " give cName cName[1] = upper(cName[1]) see "Hello " + cName 18.5 Left() Function We can get a specified number of characters from a string using the Left() function. The starting position is 1. Syntax: Left(string,count) Example: see left("Hello World!",5) # print Hello 18.4. Access String Letters 104
144.
Ring Documentation, Release1.16 18.6 Right() Function We can get a specified number of characters from a string using the Right() function. The starting position is the last character on the right. Syntax: Right(string,count) Example: see Right("Hello World!",6) # print World! 18.7 Trim() Function We can remove all leading and trailing spaces from a string using the Trim() function. Syntax: trim(string) Example: cMsg = " Welcome " see trim(cMsg) # print Welcome 18.8 Copy() Function We can duplicate a string more than one time using the copy() function. Syntax: copy(string,nCount) ---> string replicated nCount times Example see copy("***hello***",3) # print ***hello******hello******hello*** 18.9 Lines() Function We can count the number of lines inside a string using the Lines() function. Syntax: lines(string) ---> Number of lines inside the string Example: 18.6. Right() Function 105
145.
Ring Documentation, Release1.16 cStr = "Hello How are you? are you fine?" see lines(cStr) # print 3 18.10 Substr() Function We can work on sub strings inside a string using the substr() function. Using Substr() we can • Find substring • Get substring from position to end • Get Number of characters from position • Transform Substring To Another Substring 18.11 Find substring Syntax: substr(string,substring) ---> the starting position of substring in string Example: cStr = "Welcome to the Ring programming language" see substr(cStr,"Ring") # print 16 18.12 Get substring from position to end Syntax: substr(string,position) ---> Get substring starting from position to end Example: cStr = "Welcome to the Ring programming language" nPos = substr(cStr,"Ring") # nPos = 16 see substr(cStr,nPos) # print Ring programming language 18.13 Get Number of Characters From Position Syntax: substr(string,position,count) ---> Get characters starting from position Example: 18.10. Substr() Function 106
146.
Ring Documentation, Release1.16 cStr = "Welcome to the Ring programming language" nPos = substr(cStr,"Ring") # nPos = 16 see substr(cStr,nPos,4) # print Ring 18.14 Transform Substring To Another Substring Syntax: substr(string,substring,newsubstring) ---> Transformed string (Match case) substr(string,substring,newsubstring,1) ---> Transformed string (Ignore case) Example: cStr = "Welcome to the New programming language" see substr(cStr,"New","Ring") + nl # print Welcome to the Ring programming language see substr(cStr,"new","Ring",1)+ nl # print Welcome to the Ring programming language 18.15 strcmp() Function We can compare between two strings using the strcmp() function. Syntax: strcmp(cString1,cString2) ---> value = 0 if cString1 = cString2 value < 0 if cString1 < cString2 value > 0 if cString1 > cString2 Example: see strcmp("hello","hello") + nl + strcmp("abc","bcd") + nl + strcmp("bcd","abc") + nl Output: 0 -1 1 18.16 str2list() and list2str() Functions We can convert string lines to list items using the str2list() function. Also we can convert the list to a string using list2str() function. Syntax: str2list(string) ---> list contains the string lines list2str(list) ---> string contains the list items Example: 18.14. Transform Substring To Another Substring 107
147.
Ring Documentation, Release1.16 /* output: ** Items : 4 ** Item : Hello ** Item : How are you ? ** Item : are you fine ? ** Item : ok ** list2Str result = Hello ** How are you ? ** are you fine ? ** ok ** Done */ mystr = "Hello How are you ? are you fine ? ok" mylist = str2list(mystr) see "Items : " + len(mylist) + nl for x in mylist see "Item : " + x + nl next newstr = list2str(mylist) see "list2Str result = " + newstr if mystr = newstr see nl + "Done" else see nl + "Error!" ok 18.17 Merge binary characters From Ring 1.0 we can create binary strings and do operations on these strings. Starting from Ring 1.8, we can get individual characters from these strings and merge them together using the ‘+’ operator. Example: cStr = "Welcome" ? cstr[1] + cstr[2] + cStr[5] v = cstr[1] + cstr[2] + cStr[5] ? v ? len(v) c1 = cStr[1] ? c1 aList = [1,2,3] cStr = "" for item in aList cStr += int2bytes(item) next (continues on next page) 18.17. Merge binary characters 108
148.
Ring Documentation, Release1.16 (continued from previous page) ? "All String" ? len(cStr) ? "First Part" n1 = cStr[1] + cStr[2] + cStr[3] + cStr[4] ? len(n1) ? "Second Part" n2 = cStr[5] + cStr[6] + cStr[7] + cStr[8] ? len(n2) ? "Third Part" n3 = cStr[9] + cStr[10] + cStr[11] + cStr[12] ? len(n3) ? "All String" cString = cStr[1] + cStr[2] + cStr[3] + cStr[4] + cStr[5] + cStr[6] + cStr[7] + cStr[8] + cStr[9] + cStr[10] + cStr[11] + cStr[12] ? len(cString) ? ascii(cStr[1]) ? len(cStr[2]) Output: Weo Weo 3 W All String 12 First Part 4 Second Part 4 } Third Part 4 All String 12 1 1 18.17. Merge binary characters 109
149.
CHAPTER NINETEEN DATE AND TIME Inthis chapter we are going to learn about the date and time functions. 19.1 Clock() Function Syntax: Clock() ---> The number of clock ticks from program start Example: See "Calculate performance" + nl t1 = clock() for x = 1 to 1000000 next see clock() - t1 19.2 ClocksPerSecond() Function Return how many clocks in one second Syntax: clockspersecond() ---> Number of clocks in one second Example: # Wait 1 second t = clock() while clock() - t <= clockspersecond() end 110
150.
Ring Documentation, Release1.16 19.3 Time() Function We can get the system time using the Time() function. Example: See "Time : " + time() 19.4 Date() Function We can get the date using the Date() function. Syntax: Date() ---> String represent the date "dd/mm/yyyy" Example: See "Date : " + date() # Date : 24/05/2015 19.5 TimeList() Function We can print the date and the time information using the TimeList() function. Syntax: TimeList() ---> List contains the time and date information. The next table presents the list items 19.3. Time() Function 111
151.
Ring Documentation, Release1.16 index value 1 abbreviated weekday name 2 full weekday name 3 abbreviated month name 4 full month name 5 Date & Time 6 Day of the month 7 Hour (24) 8 Hour (12) 9 Day of the year 10 Month of the year 11 Minutes after hour 12 AM or PM 13 Seconds after the hour 14 Week of the year (sun-sat) 15 day of the week 16 date 17 time 18 year of the century 19 year 20 time zone 21 percent sign Example: /* Output: ** Sun abbreviated weekday name ** Sunday full weekday name ** May abbreviated month name ** May full month name ** 05/24/15 09:58:38 Date & Time ** 24 Day of the month ** 09 Hour (24) ** 09 Hour (12) ** 144 Day of the year ** 05 Month of the year ** 58 Minutes after hour ** AM AM or PM ** 38 Seconds after the hour ** 21 Week of the year (sun-sat) ** 0 day of the week ** 05/24/15 date ** 09:58:38 time ** 15 year of the century ** 2015 year ** Arab Standard Time time zone ** % percent sign */ See TimeList() Example: See "Day Name : " + TimeList()[2] # Sunday 19.5. TimeList() Function 112
152.
Ring Documentation, Release1.16 Example: See "Month Name : " + TimeList()[4] # May 19.6 AddDays() Function Syntax: AddDays(cDate,nDays) ---> Date from cDate and after nDays Example: cDate = date() see cDate + nl # 24/05/2015 cDate = adddays(cDate,10) see cDate + nl # 03/06/2015 19.7 DiffDays() Function Syntax: DiffDays(cDate1,cDate2) ---> number of days (Date1 - Date2) Example: cDate1 = date() see cDate1 + nl # 24/05/2015 cDate2 = adddays(cDate1,10) see cDate2 + nl # 03/06/2015 see "DiffDays = " + diffdays(cDate1,cDate2) + nl # -10 see "DiffDays = " + diffdays(cDate2,cDate1) + nl # 10 19.8 EpochTime() Function Syntax: EpochTime( cDate, cTime ) ---> Epoch Seconds Example: ###------------------------------------------------------------- # EpochTime() # Example --- EpochSec = EpochTime( Date(), Time() ) # Call Format: EpochSec = EpochTime( "15/07/2016", "10:15:30" ) # EpochSec = 1468577730 #--------------------------------------------------------------- Func EpochTime(Date, Time) arrayDate = split(Date, "/") (continues on next page) 19.6. AddDays() Function 113
CHAPTER TWENTY CHECK DATA TYPEAND CONVERSION In this chapter we are going to learn about the functions that can be used for • Checking Data Type • Checking Character • Conversion 20.1 Check Data Type The next functions can be used to check the data type • isstring() • isnumber() • islist() • type() • isnull() 20.2 IsString() Function Using the IsString() function we can know if the value is a string or not Syntax: IsString(value) ---> 1 if the value is a string or 0 if not Example: see isstring(5) + nl + # print 0 isstring("hello") + nl # print 1 115
155.
Ring Documentation, Release1.16 20.3 IsNumber() Function Using the IsNumber() function we can know if the value is a number or not Syntax: IsNumber(value) ---> 1 if the value is a number or 0 if not Example: see isnumber(5) + nl + # print 1 isnumber("hello") + nl # print 0 20.4 IsList() Function Using the IsList() function we can know if the value is a list or not Syntax: IsList(value) ---> 1 if the value is a list or 0 if not Example: see islist(5) + nl + # print 0 islist("hello") + nl + # print 0 islist([1,3,5]) # print 1 20.5 Type() Function We can know the type of a value using the Type() Function. Syntax: Type(value) ---> The Type as String Example: see Type(5) + nl + # print NUMBER Type("hello") + nl + # print STRING Type([1,3,5]) # print LIST 20.6 IsNULL() Function We can check the value to know if it’s null or not using the IsNULL() function Syntax: IsNULL(value) ---> 1 if the value is NULL or 0 if not Example: 20.3. IsNumber() Function 116
156.
Ring Documentation, Release1.16 see isnull(5) + nl + # print 0 isnull("hello") + nl + # print 0 isnull([1,3,5]) + nl + # print 0 isnull("") + nl + # print 1 isnull("NULL") # print 1 20.7 Check Character The next functions can be used to check character • isalnum() • isalpha() • iscntrl() • isdigit() • isgraph() • islower() • isprint() • ispunct() • isspace() • isupper() • isxdigit() 20.8 IsAlNum() Function We can test a character or a string using the IsAlNum() Function Syntax: IsAlNum(value) ---> 1 if the value is digit/letter or 0 if not Example: see isalnum("Hello") + nl + # print 1 isalnum("123456") + nl + # print 1 isalnum("ABCabc123") + nl + # print 1 isalnum("How are you") # print 0 because of spaces 20.7. Check Character 117
157.
Ring Documentation, Release1.16 20.9 IsAlpha() Function We can test a character or a string using the IsAlpha() Function Syntax: IsAlpha(value) ---> 1 if the value is a letter or 0 if not Example: see isalpha("Hello") + nl + # print 1 isalpha("123456") + nl + # print 0 isalpha("ABCabc123") + nl + # print 0 isalpha("How are you") # print 0 20.10 IsCntrl() Function We can test a character or a string using the IsCntrl() Function Syntax: IsCntrl(value) ---> 1 if the value is a control character (no printing position) or 0 if not Example: See iscntrl("hello") + nl + # print 0 iscntrl(nl) # print 1 20.11 IsDigit() Function We can test a character or a string using the IsDigit() Function Syntax: IsDigit(value) ---> 1 if the value is a digit or 0 if not Example: see isdigit("0123456789") + nl + # print 1 isdigit("0123a") # print 0 20.12 IsGraph() Function We can test a character or a string using the IsGraph() Function Syntax: IsGraph(value) ---> 1 if the value can be printed (Except space) or 0 if not Example: 20.9. IsAlpha() Function 118
158.
Ring Documentation, Release1.16 see isgraph("abcdef") + nl + # print 1 isgraph("abc def") # print 0 20.13 IsLower() Function We can test a character or a string using the IsLower() Function Syntax: IsLower(value) ---> 1 if the value is lowercase letter or 0 if not Example: see islower("abcDEF") + nl + # print 0 islower("ghi") # print 1 20.14 IsPrint() Function We can test a character or a string using the IsPrint() Function Syntax: IsPrint(value) ---> 1 if the value occupies a printing position or 0 if not Example: see isprint("Hello") + nl + # print 1 isprint("Nice to see you") + nl + # print 1 isprint(nl) # print 0 20.15 IsPunct() Function We can test a character or a string using the IsPunct() Function Syntax: IsPunct(value) ---> 1 if the value is a punctuation character or 0 if not Example: see ispunct("hello") + nl + # print 0 ispunct(",") # print 1 20.13. IsLower() Function 119
159.
Ring Documentation, Release1.16 20.16 IsSpace() Function We can test a character or a string using the IsSpace() Function Syntax: IsSpace(value) ---> 1 if the value is a white-space or 0 if not Example: see isspace(" ") + nl + # print 1 isspace("test") # print 0 20.17 IsUpper() Function We can test a character or a string using the IsUpper() Function Syntax: IsUpper(value) ---> 1 if the value is an uppercase alphabetic letter or 0 if not Example: see isupper("welcome") + nl + # print 0 isupper("WELCOME") # print 1 20.18 IsXdigit() Function We can test a character or a string using the IsXdigit() Function Syntax: IsXdigit(value) ---> 1 if the value is a hexadecimal digit character or 0 if not Example: see isxdigit("0123456789abcdef") + nl + # print 1 isxdigit("123z") # print 0 20.19 Conversion The next functions can be used for conversion • number() • string() • ascii() • char() • hex() 20.16. IsSpace() Function 120
160.
Ring Documentation, Release1.16 • dec() • str2hex() • hex2str() 20.20 Number() Function We can convert strings to numbers using the Number() function or the + operator. Syntax: Number(string) ---> Number 0 + string ---> Number Example: see number("5") + 5 + nl # print 10 see 0 + "10" + 2 # print 12 20.21 String() Function We can convert numbers to strings using the String() function or the + operator. Syntax: String(number) ---> String "" + number ---> String Example: see string(5) + 5 + nl # print 55 see "" + 10 + 2 # print 102 20.22 Ascii() Function We can get the ASCII code for a letter using the Ascii() function Syntax: Ascii(character) ---> ASCII Code Example: See ascii("m") + nl + # print 109 ascii("M") # print 77 20.20. Number() Function 121
161.
Ring Documentation, Release1.16 20.23 Char() Function We can convert the ASCII code to character using the Char() function. Syntax: Char(ASCII Code) ---> character Example: See char(109) + nl + # print m char(77) # print M 20.24 Hex() Function We can convert decimal to hexadecimal using the Hex() function. Syntax: Hex(decimal) ---> hexadecimal Example: See hex(10) + nl + # print a hex(200) # print c8 20.25 Dec() Function We can convert hexadecimal to decimal using the Dec() function Syntax: Dec(hexadecimal) ---> decimal Example: See dec("a") + nl + # print 10 dec("c8") # print 200 20.26 Str2hex() Function We can convert string characters to hexadecimal characters using the Str2hex() function. Syntax: Str2hex(string) ---> hexadecimal string Example: See str2hex("hello") # print 68656c6c6f 20.23. Char() Function 122
162.
Ring Documentation, Release1.16 20.27 Hex2str() Function We can convert hexadecimal characters to string using the Hex2str() function Syntax: Hex2Str(Hexadecimal string) ---> string Example: See hex2str("68656c6c6f") # print hello 20.27. Hex2str() Function 123
163.
CHAPTER TWENTYONE MATHEMATICAL FUNCTIONS In thischapter we are going to learn about the mathematical functions 21.1 List of functions The Ring programming language comes with the next mathematical functions Function Description sin(x) Returns the sine of an angle of x radians cos(x) Returns the cosine of an angle of x radians tan(x) Returns the tangent of an angle of x radians asin(x) Returns the principal value of the arc sine of x, expressed in radians acos(x) Returns the principal value of the arc cosine of x, expressed in radians atan(x) Returns the principal value of the arc tangent of x, expressed in radians atan2(y,x) Returns the principal arc tangent of y/x, in the interval [-pi,+pi] radians sinh(x) Returns the hyperbolic sine of x radians cosh(x) Returns the hyperbolic cosine of x radians tanh(x) Returns the hyperbolic tangent of x radians exp(x) Returns the value of e raised to the xth power log(x) Returns the natural logarithm of x (the base of e) log(x,b) Returns the logarithm of x to the base of b log10(x) Returns the common logarithm (base-10 logarithm) of x ceil(x) Returns the smallest integer value greater than or equal to x floor(x) Returns the largest integer value less than or equal to x fabs(x) Returns the absolute value of x. pow(x,y) Returns x raised to the power of y sqrt(x) Returns the square root of x random(x) Returns a random number in the range [0,x] srandom(x) Initialize random number generator unsigned(n,n,c) Perform operation using unsigned numbers decimals(n) Determine the decimals digits after the point in float/double numbers 124
164.
Ring Documentation, Release1.16 21.2 Example See "Mathematical Functions" + nl See "Sin(0) = " + sin(0) + nl See "Sin(90) radians = " + sin(90) + nl See "Sin(90) degree = " + sin(90*3.14/180) + nl See "Cos(0) = " + cos(0) + nl See "Cos(90) radians = " + cos(90) + nl See "Cos(90) degree = " + cos(90*3.14/180) + nl See "Tan(0) = " + tan(0) + nl See "Tan(90) radians = " + tan(90) + nl See "Tan(90) degree = " + tan(90*3.14/180) + nl See "asin(0) = " + asin(0) + nl See "acos(0) = " + acos(0) + nl See "atan(0) = " + atan(0) + nl See "atan2(1,1) = " + atan2(1,1) + nl See "sinh(0) = " + sinh(0) + nl See "sinh(1) = " + sinh(1) + nl See "cosh(0) = " + cosh(0) + nl See "cosh(1) = " + cosh(1) + nl See "tanh(0) = " + tanh(0) + nl See "tanh(1) = " + tanh(1) + nl See "exp(0) = " + exp(0) + nl See "exp(1) = " + exp(1) + nl See "log(1) = " + log(1) + nl See "log(2) = " + log(2) + nl See "log10(1) = " + log10(1) + nl See "log10(2) = " + log10(2) + nl See "log10(10) = " + log10(10) + nl See "Ceil(1.12) = " + Ceil(1.12) + nl See "Ceil(1.72) = " + Ceil(1.72) + nl See "Floor(1.12) = " + floor(1.12) + nl See "Floor(1.72) = " + floor(1.72) + nl See "fabs(1.12) = " + fabs(1.12) + nl See "fabs(1.72) = " + fabs(1.72) + nl See "pow(2,3) = " + pow(2,3) + nl see "sqrt(16) = " + sqrt(16) + nl Program Output: Mathematical Functions Sin(0) = 0 Sin(90) radians = 0.89 Sin(90) degree = 1.00 Cos(0) = 1 Cos(90) radians = -0.45 Cos(90) degree = 0.00 (continues on next page) 21.2. Example 125
165.
Ring Documentation, Release1.16 (continued from previous page) Tan(0) = 0 Tan(90) radians = -2.00 Tan(90) degree = 1255.77 asin(0) = 0 acos(0) = 1.57 atan(0) = 0 atan2(1,1) = 0.79 sinh(0) = 0 sinh(1) = 1.18 cosh(0) = 1 cosh(1) = 1.54 tanh(0) = 0 tanh(1) = 0.76 exp(0) = 1 exp(1) = 2.72 log(1) = 0 log(2) = 0.69 log10(1) = 0 log10(2) = 0.30 log10(10) = 1 Ceil(1.12) = 2 Ceil(1.72) = 2 Floor(1.12) = 1 Floor(1.72) = 1 fabs(1.12) = 1.12 fabs(1.72) = 1.72 pow(2,3) = 8 sqrt(16) = 4 21.3 Random() Function The Random() function generate a random number and we can set the maximum value (optional). Syntax: Random(x) ---> Random number in the range [0,x] Example: for x = 1 to 20 see "Random number : " + random() + nl + "Random number Max (100) : " + random(100) + nl next Program Output: Random number : 31881 Random number Max (100) : 80 Random number : 5573 Random number Max (100) : 63 Random number : 2231 Random number Max (100) : 43 Random number : 12946 Random number Max (100) : 39 (continues on next page) 21.3. Random() Function 126
166.
Ring Documentation, Release1.16 (continued from previous page) Random number : 22934 Random number Max (100) : 48 Random number : 4690 Random number Max (100) : 52 Random number : 13196 Random number Max (100) : 65 Random number : 30390 Random number Max (100) : 87 Random number : 4327 Random number Max (100) : 77 Random number : 12456 Random number Max (100) : 17 Random number : 28438 Random number Max (100) : 13 Random number : 30503 Random number Max (100) : 6 Random number : 31769 Random number Max (100) : 94 Random number : 8274 Random number Max (100) : 65 Random number : 14390 Random number Max (100) : 90 Random number : 28866 Random number Max (100) : 12 Random number : 24558 Random number Max (100) : 70 Random number : 29981 Random number Max (100) : 77 Random number : 12847 Random number Max (100) : 63 Random number : 6632 Random number Max (100) : 60 21.4 SRandom() Function The SRandom() function initialize random number generator. Syntax: SRandom(x) 21.5 Unsigned() Function We can use unsigned numbers using the Unsigned() function. Syntax: Unsigned(nNum1,nNum2,cOperator) --> result of cOperator operation on nNum1,nNum2 Example: 21.4. SRandom() Function 127
167.
Ring Documentation, Release1.16 see oat_hash("hello") + nl # Jenkins hash function - https://en.wikipedia.org/wiki/Jenkins_hash_function func oat_hash cKey h = 0 for x in cKey h = unsigned(h,ascii(x),"+") h = unsigned(h,unsigned(h,10,"<<"),"+") r = unsigned(h,6,">>") h = unsigned(h, r,"^") next h = unsigned(h,unsigned(h,3,"<<"),"+") h = unsigned(h,unsigned(h,11,">>"),"^") h = unsigned(h,unsigned(h,15,"<<"),"+") return h Output: 3372029979.00 21.6 Decimals() Functions We can determine the decimals numbers count after the point in float/double numbers using the decimals() function. Syntax: Decimals(nDecimalsCount) Example: x = 1.1234567890123 for d = 0 to 14 decimals(d) see x + nl next Output: 1 1.1 1.12 1.123 1.1235 1.12346 1.123457 1.1234568 1.12345679 1.123456789 1.1234567890 1.12345678901 1.123456789012 1.1234567890123 1.12345678901230 21.6. Decimals() Functions 128
168.
Ring Documentation, Release1.16 21.7 Using _ in numbers We can use _ between numbers digits. Example: x = 1_000_000 see type(x)+nl see x+1+nl Output: NUMBER 100000001 21.8 Using f after numbers We can use the ‘f’ letter after numbers. Example: x = 19.99f see type(x) + nl Output: NUMBER 21.9 Using Hexadecimal Numbers We can write Hexadecimal number by preceding with “0x” or “0X” Example: x = 0x10 ? x # 16 x = 0xff ? x # 255 x = 0x0A ? x # 10 ? 0xFFFF # 65535 ? 0x0A + 1 # 10+1 = 11 21.7. Using _ in numbers 129
Ring Documentation, Release1.16 • fwrite() • fexists() • direxists() • getpathtype() • Numbers and Bytes 22.1 Read() Function We can read the file content using the Read() function Syntax: Read(cFileName) ---> String contains the file content Example: see read("myfile.txt") The read function can read binary files too Example: see read("myapp.exe") 22.2 Write() Function We can write string to file using the Write() function The write function can write binary data to binary files. Syntax: Write(cFileName,cString) # write string cString to file cFileName Example: # copy file cFile = read("ring.exe") write("ring2.exe",cFile) 22.3 Dir() Function We can get the folder contents (files & sub folders) using the Dir() function. Syntax: Dir(cFolderPath) ---> List contains files & sub folders. This function returns a list and each list item is a list of two items • File/sub folder name 22.1. Read() Function 131
171.
Ring Documentation, Release1.16 • Type (0 = File , 1 = Folder/Directory) Example: see "Testing DIR() " + nl mylist = dir("C:myfolder") for x in mylist if x[2] see "Directory : " + x[1] + nl else see "File : " + x[1] + nl ok next see "Files count : " + len(mylist) 22.4 Rename() Function We can rename files using the Rename() function Syntax: Rename(cOldFileName,cNewFileName) ---> Number ( Status: Success (0) , Error (-1) ) Example: rename("file.txt","help.txt") 22.5 Remove() Function We can delete a file using the Remove() function Syntax: Remove(cFileName) Example: remove("test.txt") 22.6 Fopen() Function We can open a file using the Fopen() function Syntax: Fopen(cFileName,cMode) ---> File Handle 22.4. Rename() Function 132
172.
Ring Documentation, Release1.16 Mode Description “r” Reading (The file must exist) “w” Writing (create empty file / overwrite) “a” Appends (create file if it doesn’t exist) “r+” update (reading/writing) “w+” Create empty file (reading/writing) “a+” reading & appending 22.7 Fclose() Function When we open a file using fopen() function, we can close it using the Fclose() function Syntax: Fclose(file handle) 22.8 Fflush() Function We can flushes the output buffer of a stream using the Fflush() function Syntax: Fflush(file handle) 22.9 Freopen() Function We can open another file using the same file handle and at the same time close the old file Syntax: Freopen(cFileName,cMode,file handle) ---> file handle Example: freopen("myprogoutput.txt","w+",stdout) see "welcome" + nl for x = 1 to 10 see x + nl next /* ** Read : https://en.wikipedia.org/wiki/Device_file#Device_files ** The next code is not portable, we can use iswindows() before ** using it and we can write special code for each operating system. */ freopen("CON","w",stdout) # For Microsoft Windows see "Done" + nl # print to stdout again Output: 22.7. Fclose() Function 133
173.
Ring Documentation, Release1.16 # Output to stdout Done # Output to file : myprogoutput.txt welcome 1 2 3 4 5 6 7 8 9 10 22.10 Tempfile() Function The function Tempfile() creates a temp. file (binary). The file will be deleted automatically when the stream is closed Syntax: TempFile() ---> file handle 22.11 Tempname() Function We can generate temp. file name using the Tempname() function The generated name will be different from the name of any existing file Syntax: Tempname() ---> generated file name as string 22.12 Fseek() Function We can set the file position of the stream using the Fseek() function Syntax: Fseek(file handle, nOffset, nWhence) ---> zero if successful The next table presents the nWhence values Value Description 0 Beginning of file 1 Current position 2 End of file 22.10. Tempfile() Function 134
174.
Ring Documentation, Release1.16 22.13 Ftell() Function We can know the current file position of a stream using the Ftell() function Syntax: Ftell(file handle) ---> file position as number 22.14 Rewind() Function We can set the file position to the beginning of the file using the Rewind() function Syntax: Rewind(file handle) 22.15 Fgetpos() Function We can get handle to the current file position using the Fgetpos() function Syntax: Fgetpos(file handle) ---> position handle 22.16 Fsetpos() Function We can set the current file position using the Fsetpos() function Syntax: Fsetpos(file handle,position handle) 22.17 Clearerr() Function We can clear the EOF error and the error indicators of a stream using the clearerr() function Syntax: Clearerr(file handle) 22.13. Ftell() Function 135
175.
Ring Documentation, Release1.16 22.18 Feof() Function We can test the end-of-file indicator using the Feof() function Syntax: Feof(file handle) ---> returns 1 if EOF and 0 if not 22.19 Ferror() Function We can test the error indicator of a given stream using the Ferror() function Syntax: Ferror(file handle) ---> returns 1 if error and 0 if not 22.20 Perror() Function We can print error message to the stderr using the Perror() function Syntax: Perror(cErrorMessage) 22.21 Fgetc() Function We can get the next character from the stream using the Fgetc() function Syntax: Fgetc(file handle) ---> returns character or EOF 22.22 Fgets() Function We can read new line from the stream using the Fgets() function Syntax: Fgets(file handle,nSize) ---> string The function stop when nSize characters are read, new line character is read or EOF. 22.18. Feof() Function 136
176.
Ring Documentation, Release1.16 22.23 Fputc() Function We can write a character to the stream using the Fputc() function Syntax: Fputc(file handle,cChar) 22.24 Fputs() Function We can write a string to the stream using the Fputs() function Syntax: Fputs(file handle,cString) 22.25 Ungetc() Function We can push a character to the stream using the Ungetc() function The character will be available for the next read Syntax: Ungetc(file handle,character) 22.26 Fread() Function We can read data from a stream using the Fread() function Syntax: Fread(file handle,nSize) 22.27 Fwrite() Function We can write data to a stream using the Fwrite() function Syntax: Fwrite(file handle,cString) 22.23. Fputc() Function 137
177.
Ring Documentation, Release1.16 22.28 Fexists() Function We can check if a file exists using the Fexists() function Syntax: Fexists(cFileName) ---> returns 1 if the file exists Example: see fexists("b:mahmoudappsringring.exe") + nl + fexists("b:mahmoudappsringring2.exe") + nl Output: 1 0 22.29 Direxists() Function Syntax: Direxists(cDirPath) ---> returns 1 if the directory exists Example: ? direxists("b:ring") + nl + direxists("b:ringbin2") Output: 1 0 22.30 Getpathtype() Function We can get the type a given path (file or directory) using the Getpathtype() function Syntax: Getpathtype(cPath) ---> 0 if the path doesn't exists 1 if it corresponds to existing file 2 if it corresponds to existing directory -1 if the path exists but has an unknown type (e.g. a pipe) Example: ? Getpathtype("b:ringbinring.exe") + nl + Getpathtype("b:ring") + nl + Getpathtype("b:ringbin2") Output: 22.28. Fexists() Function 138
178.
Ring Documentation, Release1.16 1 2 0 22.31 Example The next program test some of the file functions See "testing file functions" + nl See "open file" + nl fp = fopen(exefolder() + "../tests/scripts/s65.ring","r") See "reopen" + nl fp = freopen(exefolder() + "../tests/scripts/s78.ring","r",fp) See "close file" + nl fclose(fp) see "temp file" + nl fp = tempfile() fclose(fp) see "temp name" + nl see tempname() + nl remove(exefolder() + "../tests/scripts/mytest2.txt") write(exefolder() + "../tests/scripts/tests1.txt","hello") rename(exefolder() + "../tests/scripts/test1.txt",exefolder() + "../tests/scripts/mytests2.txt") see "print file" + nl fp = fopen(exefolder() + "../samples/fromdoc/filefuncs.ring","r") r = fgetc(fp) while isstring(r) see r r = fgetc(fp) end fclose(fp) see nl+"print line from the file" + nl fp = fopen(exefolder() + "../samples/fromdoc/filefuncs.ring","r") r = fgets(fp,33) see r + nl fclose(fp) fp = fopen(exefolder() + "../tests/scripts/test78.txt","w+") fseek(fp,0,2) # goto end of file fputc(fp,"t") fputc(fp,"e") fputc(fp,"s") fputc(fp,"t") fputs(fp,"tests2") fclose(fp) see "print file" + nl see read(exefolder() + "../tests/scripts/test78.txt") (continues on next page) 22.31. Example 139
179.
Ring Documentation, Release1.16 (continued from previous page) fp = fopen(exefolder() + "../tests/scripts/test78.txt","r") see "testing ungetc() " + nl for x = 1 to 3 r = fgetc(fp) see r + nl ungetc(fp,r) next fclose(fp) see "testing fread() " + nl fp = fopen(exefilename(),"rb") r = fread(fp,100) see r + nl fclose(fp) see "testing fwrite() " + nl fp = fopen(exefolder() + "../tests/scripts/test1.txt","wb") fwrite(fp,r) fclose(fp) The next example print part of the content of a binary file see "Testing: fread()" +" FileName: "+ exefilename() +nl +nl fp = fopen(exefilename(),"rb") r = fread(fp,800) for n =1 to len(r) if isprint(substr(r, n, 1)) see substr(r, n, 1) else see "." ok ### 80 char per line if n % 80 = 0 see nl ok next fclose(fp) 22.32 Numbers and Bytes The next functions to convert between Numbers and Bytes. • Int2Bytes() • Float2Bytes() • Double2Bytes() • Bytes2Int() • Bytes2Float() • Bytes2Double() Example: 22.32. Numbers and Bytes 140
180.
Ring Documentation, Release1.16 see "Test Int2Bytes() and Bytes2Int() - Value : 77" + nl r = Int2Bytes(77) see "Int Size : " + len(r) + nl see r + nl see Bytes2Int(r) + nl see "Test Float2Bytes() and Bytes2Float() - Value 77.12" + nl r = Float2Bytes(77.12) see "Float Size : " + len(r) + nl see r + nl see Bytes2Float(r) + nl see "Test Double2Bytes() and Bytes2Double() - Value 9999977.12345" + nl r = Double2Bytes(9999977.12345) see "Double Size : " + len(r) + nl see r + nl decimals(5) see Bytes2Double(r) + nl 22.32. Numbers and Bytes 141
181.
CHAPTER TWENTYTHREE SYSTEM FUNCTIONS In thischapter we are going to learn about the system functions • System() • SysGet() • SysSet() • SysUnset() • IsMSDOS() • IsWindows() • IsWindows64() • IsUnix() • IsMacOSX() • IsLinux() • IsFreeBSD() • IsAndroid() • GetArch() • Windowsnl() • Get Command Line Arguments • Get Active Source File Name • CurrentDir() • ExeFileName() • ChDir() • ExeFolder() • Version() • Shutdown() 142
182.
Ring Documentation, Release1.16 23.1 System() Function We can execute system commands using the system() function Syntax: System(cCommand) Example: System("myapp.exe") # Run myapp.exe System("ls") # print list of files 23.2 SysGet() Function We can get environment variables using the Get() function Syntax: SysGet(cVariable) Example: see sysget("path") # print system path information 23.3 SysSet() Function We can set environment variables using the SysSet() function SysSet(cVariable, cValue) ---> Returns 1 for success and return 0 for failure 23.4 SysUnset() Function We can delete an environment variables using the SysUnset() function SysUnset(cVariable) ---> Returns 1 for success and return 0 for failure 23.5 IsMSDOS() Function We can check if the operating system is MSDOS or not using the IsMSDOS() function Syntax: IsMSDOS() ---> Returns 1 if the operating system is MS-DOS, Returns 0 if it's not 23.1. System() Function 143
183.
Ring Documentation, Release1.16 23.6 IsWindows() Function We can check if the operating system is Windows or not using the IsWindows() function Syntax: IsWindows() ---> Returns 1 if the operating system is Windows, Returns 0 if it's not 23.7 IsWindows64() Function We can check if the operating system is Windows 64bit or not using the IsWindows64() function Syntax: IsWindows64() ---> Returns 1 if the operating system is Windows64, Returns 0 if it's ˓ →not 23.8 IsUnix() Function We can check if the operating system is Unix or not using the IsUnix() function Syntax: IsUnix() ---> Returns 1 if the operating system is Unix, Returns 0 if it's not 23.9 IsMacOSX() Function We can check if the operating system is macOS or not using the IsMacOSX() function Syntax: IsMacOSX() ---> Returns 1 if the operating system is Mac OS X, Returns 0 if it's not 23.10 IsLinux() Function We can check if the operating system is Linux or not using the IsLinux() function Syntax: IsLinux() ---> Returns 1 if the operating system is Linux, Returns 0 if it's not 23.6. IsWindows() Function 144
184.
Ring Documentation, Release1.16 23.11 IsFreeBSD() Function We can check if the operating system is FreeBSD or not using the IsFreeBSD() function Syntax: IsFreeBSD() ---> Returns 1 if the operating system is FreeBSD, Returns 0 if it's not 23.12 IsAndroid() Function We can check if the operating system is Android or not using the IsAndroid() function Syntax: IsAndroid() ---> Returns 1 if the operating system is Android, Returns 0 if it's not 23.13 Example see "IsMSDOS() --> " + ismsdos() + nl see "IsWindows() --> " + iswindows() + nl see "IsWindows64() --> " + iswindows64() + nl see "IsUnix() --> " + isunix() + nl see "IsMacOSX() --> " + ismacosx() + nl see "IsLinux() --> " + islinux() + nl see "IsFreeBSD() --> " + isfreebsd() + nl see "IsAndroid() --> " + isandroid() + nl Output: IsMSDOS() --> 0 IsWindows() --> 1 IsWindows64() --> 0 IsUnix() --> 0 IsMacOSX() --> 0 IsLinux() --> 0 IsFreeBSD() --> 0 IsAndroid() --> 0 23.14 GetArch() Function We can detect the architecture of the Ring executable using the GetArch() function Syntax: GetArch() ---> cString (The name of the architecture of the Ring executable) Possible values are: 23.11. IsFreeBSD() Function 145
185.
Ring Documentation, Release1.16 x86 x64 arm64 arm unknown Example: switch getarch() on "x86" ? "x86 32bit architecture" on "x64" ? "x64 64bit architecture" on "arm64" ? "ARM64 64bit architecture" on "arm" ? "ARM 32bit architecture" other ? "Unknown architecture" off 23.15 Windowsnl() Function We can get the windows new line string using the Windowsnl() function. Syntax: WindowsNL() ---> Returns a string contains CR+LF = CHAR(13) + CHAR(10) Example: cStr = read("input.txt") if iswindows() cStr = substr(cStr,windowsnl(),nl) ok aList = str2list(cStr) # to do - list items processing using "for in" cStr = list2str(aList) if iswindows() cStr = substr(cStr,nl,windowsnl()) ok write("ouput.txt",cStr) 23.15. Windowsnl() Function 146
186.
Ring Documentation, Release1.16 23.16 Get Command Line Arguments We can get the command line arguments passed to the ring script using the sysargv variable. The sysargv variable is a list contains the command line parameters. Example see copy("=",30) + nl see "Command Line Parameters" + nl see "Size : " + len(sysargv) + nl see sysargv see copy("=",30) + nl if len(sysargv) < 4 return ok nStart = sysargv[3] nEnd = sysargv[4] for x = nStart to nEnd see x + nl next Output b:mahmoudappsring>ring testssyspara.ring 1 10 ============================== Command Line Parameters Size : 4 ring testssyspara.ring 1 10 ============================== 1 2 3 4 5 6 7 8 9 10 23.17 Get Active Source File Name We can get the active source file name (*.ring) using the filename() function Syntax: filename() ---> String contains the active source file name. Example: see "Active Source File Name : " + filename() + nl Output: 23.16. Get Command Line Arguments 147
187.
Ring Documentation, Release1.16 Active Source File Name : testsfilename.ring Example: if sysargv[2] = filename() see "I'm the main program file!" + nl # we can run tests here! else see "I'm a sub file in a program" + nl ok 23.18 PrevFileName() Function Using the PrevFileName() function we can get the previous active source file name. The previous file would be the file of the caller function, Or the file of the function that we called before calling PrevFileName(). Syntax: prevfilename() ---> String contains the previous source file name. Example: The next function in stdlib.ring uses the PrevFileName() to know if the file of the caller function is the main source file of the program or not. Func IsMainSourceFile if PrevFileName() = sysargv[2] return true ok return false 23.19 CurrentDir() Function Return the path of the current directory Syntax: CurrentDir() ---> String contains the path of the current directory 23.20 ExeFileName() Function Return the Ring executable file name Syntax: exefilename() ---> String contains the Ring executable file name 23.18. PrevFileName() Function 148
188.
Ring Documentation, Release1.16 23.21 ChDir() Function Change the current directory Syntax: ChDir(cNewPath) 23.22 ExeFolder() Function Return the Ring executable file path Syntax: exefolder() ---> String contains the Ring executable path 23.23 Version() Function Return the Ring version Syntax: version() ---> String contains the Ring version Output: 1.16 23.24 Shutdown() Function Close the application Syntax: shutdown(nStatus) ---> Close the application 23.25 NofProcessors() Function We can detect the number of processors using the NofProcessors() Function Syntax: NofProcessors() ---> nProcessors Example: ? NofProcessors() 23.21. ChDir() Function 149
189.
CHAPTER TWENTYFOUR EVAL() AND DEBUGGING Inthis chapter we are going to learn about • Error Handling using Try/Catch/Done • Eval() function • Raise() function • Assert() function 24.1 Try/Catch/Done Syntax: Try Statements... Catch Statements... Done The statements in the Try block will be executed, if any error happens then the statements in the catch block will be executed. Inside the catch block we can use the variable cCatchError to get the error message Example: Try see 5/0 Catch see "Catch!" + nl + cCatchError Done Output: Catch! Error (R1) : Can't divide by zero ! 150
190.
Ring Documentation, Release1.16 24.2 Eval() Function We can execute code during the runtime from string using the Eval() function Syntax: Eval(cCode) Example: Eval("nOutput = 5+2*5 " ) See "5+2*5 = " + nOutput + nl Eval("for x = 1 to 10 see x + nl next") Eval("func test see 'message from test!' ") test() Output: 5+2*5 = 15 1 2 3 4 5 6 7 8 9 10 message from test! We can use the Return command to return a value Example: see Eval("return 5*5") Output: 25 24.3 Raise() Function We can raise an exception using the Raise() function Syntax: Raise(cErrorMessage) The function will display the error message then end the execution of the program. We can use Try/Catch/Done to avoid exceptions generated by raise() function. Example: 24.2. Eval() Function 151
191.
Ring Documentation, Release1.16 nMode = 10 if nMode < 0 or nMode > 5 raise("Error : nMode not in the range 1:4") ok Output: Line 4 Error : nMode not in the range 1:4 In raise in file testsraise.ring Example: try testmode(6) catch see "avoid raise!" done testmode(-1) func testmode nMode if nMode < 0 or nMode > 5 raise("Error : nMode not in the range 1:4") ok Output: avoid raise! Line 12 Error : nMode not in the range 1:4 In raise In function testmode() in file testsraise2.ring called from line 7 in file testsraise2.ring 24.4 Assert() Function We can use the Assert() function to test conditions before executing the code If the test fail the program will be terminated with an error message contains the assert condition. Syntax: Assert( condition ) Example: x = 10 assert( x = 10) assert( x = 100 ) Output: Line 3 Assertion Failed! In assert in file testsassert.ring 24.4. Assert() Function 152
192.
CHAPTER TWENTYFIVE DEMO PROGRAMS In thischapter we will see simple demo programs • Language Shell • Main Menu 25.1 Language Shell We can create simple interactive programming environment using the next program while true see nl + "code:> " give cCode try eval(cCode) catch see cCatchError done end Output: code:> see "hello world" hello world code:> for x = 1 to 10 see x + nl next 1 2 3 4 5 6 7 8 9 10 code:> func test see "Hello from test" + nl code:> test() Hello from test code:> bye 153
193.
Ring Documentation, Release1.16 25.2 Main Menu Example: # Demo Program while true see " Main Menu =========== [1] Say Hello [2] Sum two numbers [3] Stars [4] Fact [5] Exit " give nMenu see nl # we can use Switch-ON-Other-OFF instead of IF-BUT-ELSE-OK Switch nMenu On 1 sayhello() On 2 Sum() On 3 Stars() On 4 see "Enter Number : " give x see "Output : " Try see Fact(number(x)) Catch see "Error in parameters!" + nl Done On "5" return Other see "bad option" + nl Off end func sayhello see "Enter your name ? " give fname see "Hello " + fname + nl func sum see "number 1 : " give num1 see "number 2 : " give num2 see "Sum : " see 0 + num1 + num2 func stars for x = 1 to 10 see space(8) for y = 1 to x see "*" next see nl next func fact x if x = 0 return 1 else return x * fact(x-1) ok (continues on next page) 25.2. Main Menu 154
194.
Ring Documentation, Release1.16 (continued from previous page) func space x y = "" for t=1 to x y += " " next return y Output: Main Menu =========== [1] Say Hello [2] Sum two numbers [3] Stars [4] Fact [5] Exit 1 Enter your name ? Mahmoud Fayed Hello Mahmoud Fayed Main Menu =========== [1] Say Hello [2] Sum two numbers [3] Stars [4] Fact [5] Exit 2 number 1 : 3 number 2 : 4 Sum : 7 Main Menu =========== [1] Say Hello [2] Sum two numbers [3] Stars [4] Fact [5] Exit 3 * ** *** **** ***** ****** ******* ******** ********* ********** Main Menu =========== (continues on next page) 25.2. Main Menu 155
195.
Ring Documentation, Release1.16 (continued from previous page) [1] Say Hello [2] Sum two numbers [3] Stars [4] Fact [5] Exit 4 Enter Number : 5 Output : 120 Main Menu =========== [1] Say Hello [2] Sum two numbers [3] Stars [4] Fact [5] Exit 5 25.2. Main Menu 156
196.
CHAPTER TWENTYSIX ODBC FUNCTIONS This chaptercontains the ODBC functions provided by the Ring programming language. • odbc_init() • odbc_drivers() • odbc_datasources() • odbc_close() • odbc_connect() • odbc_disconnect() • odbc_execute() • odbc_colcount() • odbc_fetch() • odbc_getdata() • odbc_tables() • odbc_columns() • odbc_autocommit() • odbc_commit() • odbc_rollback() Before using the next function load the odbclib.ring library load "odbclib.ring" # Use ODBC functions 26.1 odbc_init() Function We can create ODBC Handle using the odbc_init() function Syntax: odbc_init() ---> ODBC Handle 157
197.
Ring Documentation, Release1.16 26.2 odbc_drivers() Function We can get a list of ODBC drivers using the odbc_drivers() function Syntax: odbc_drivers(ODBC Handle) ---> List of Drivers 26.3 odbc_datasources() Function We can get a list of ODBC data sources using the odbc_datasources() function Syntax: odbc_datasources(ODBC Handle) ---> List of Data sources 26.4 odbc_close() Function After the end of using ODBC functions we can free resources using ODBC_Close() function Syntax: odbc_close(ODBC Handle) 26.5 Print List of ODBC Drivers The next example print a list of ODBC drivers. See "ODBC test 1" + nl oODBC = odbc_init() See "Drivers " + nl see odbc_drivers(oODBC) odbc_close(oODBC) Output: ODBC test 1 Drivers Microsoft Access-Treiber (*.mdb) - SQLLevel=0 Driver do Microsoft Paradox (*.db ) - SQLLevel=0 Driver do Microsoft Excel(*.xls) - SQLLevel=0 Microsoft Text Driver (*.txt; *.csv) - SQLLevel=0 Driver da Microsoft para arquivos texto (*.txt; *.csv) - SQLLevel=0 Microsoft dBase-Treiber (*.dbf) - SQLLevel=0 SQL Server - CPTimeout=60 Microsoft Excel Driver (*.xls) - SQLLevel=0 Driver do Microsoft dBase (*.dbf) - SQLLevel=0 Microsoft Paradox-Treiber (*.db ) - SQLLevel=0 Microsoft ODBC for Oracle - CPTimeout=120 Microsoft Text-Treiber (*.txt; *.csv) - SQLLevel=0 (continues on next page) 26.2. odbc_drivers() Function 158
198.
Ring Documentation, Release1.16 (continued from previous page) Microsoft Excel-Treiber (*.xls) - SQLLevel=0 Microsoft Access Driver (*.mdb) - SQLLevel=0 Driver do Microsoft Access (*.mdb) - SQLLevel=0 Microsoft Paradox Driver (*.db ) - SQLLevel=0 Microsoft dBase Driver (*.dbf) - SQLLevel=0 Microsoft Access Driver (*.mdb, *.accdb) - UsageCount=3 Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb) - UsageCount=3 Microsoft Access Text Driver (*.txt, *.csv) - UsageCount=3 SQL Server Native Client 10.0 - UsageCount=1 SQL Server Native Client 11.0 - UsageCount=1 Microsoft Access dBASE Driver (*.dbf, *.ndx, *.mdx) - UsageCount=3 Microsoft Access Paradox Driver (*.db) - UsageCount=3 MySQL ODBC 5.3 ANSI Driver - UsageCount=1 MySQL ODBC 5.3 Unicode Driver - UsageCount=1 ODBC Driver 11 for SQL Server - UsageCount=1 Lianja ODBC Driver - CPTimeout=60 Microsoft Visual FoxPro Driver - UsageCount=1 Microsoft Visual FoxPro-Treiber - UsageCount=1 Driver para o Microsoft Visual FoxPro - UsageCount=1 Microsoft FoxPro VFP Driver (*.dbf) - UsageCount=1 26.6 Print List of ODBC Data Sources The next example print a list of ODBC data sources. See "ODBC test 2" + nl pODBC = odbc_init() See "Data Sources " + nl see odbc_datasources(pODBC) odbc_close(pODBC) Output: ODBC test 2 Data Sources Excel Files - Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb) MS Access Database - Microsoft Access Driver (*.mdb, *.accdb) Customer - Microsoft Access Driver (*.mdb) IdCardData - Microsoft Access Driver (*.mdb) MyProjectData2 - Microsoft Access Driver (*.mdb) MyData - Microsoft Access Driver (*.mdb) MonprojetData - Microsoft Access Driver (*.mdb) dBASE Files - Microsoft Access dBASE Driver (*.dbf, *.ndx, *.mdx) myvfpdata - Microsoft Visual FoxPro Driver FACTORYDATA - Microsoft Access Driver (*.mdb) TRAININGSYSDATA - Microsoft Access Driver (*.mdb) RVCSYSDATASQLDB - SQL Server Native Client 11.0 PWCTRVCDATA - Microsoft Access Driver (*.mdb) MyCompany - Microsoft Access Driver (*.mdb) HCS - Microsoft Access Driver (*.mdb) HCS2 - Microsoft Access Driver (*.mdb, *.accdb) MyProjectData - Microsoft Access Driver (*.mdb) Xtreme Sample Database 2008 - Microsoft Access Driver (*.mdb) Lianja_Southwind - Lianja ODBC Driver (continues on next page) 26.6. Print List of ODBC Data Sources 159
199.
Ring Documentation, Release1.16 (continued from previous page) Visual FoxPro Database - Microsoft Visual FoxPro Driver Visual FoxPro Tables - Microsoft Visual FoxPro Driver 26.7 odbc_connect() Function We can connect to the database using the odbc_connect() function. Syntax: odbc_connect(ODBC Handle, cConnectionString) 26.8 odbc_disconnect() Function We can close the connection to the database using the odbc_disconnect() function. Syntax: odbc_disconnect(ODBC Handle) 26.9 Open and Close Connection The next example connect to the database then close the connection See "ODBC test 3" + nl pODBC = odbc_init() See "Connect to database" + nl see odbc_connect(pODBC,"DBQ=test.mdb;Driver={Microsoft Access Driver (*.mdb)}") + nl See "disconnect" + nl odbc_disconnect(pODBC) See "Close database..." + nl odbc_close(pODBC) Output: ODBC test 3 Connect to database 1 disconnect Close database... 26.7. odbc_connect() Function 160
200.
Ring Documentation, Release1.16 26.10 odbc_execute() Function We can execute SQL Statements on the database using the odbc_execute() function. Syntax: odbc_execute(ODBC Handle, cSQLStatement) 26.11 odbc_colcount() Function We can get columns count in the query result using the odbc_colcount() function. Syntax: odbc_colcount(ODBC Handle) ---> Columns Count as Number 26.12 odbc_fetch() Function We can fetch a row from the query result using the odbc_fetch() function. Syntax: odbc_fetch(ODBC Handle) 26.13 odbc_getdata() Function We can get column value from the fetched row using the odbc_getdata() function. Syntax: odbc_getdata(ODBC Handle, nColumnNumber) ---> Column Value 26.14 Execute Query and Print Result The next example execute query then print the query result. See "ODBC test 4" + nl pODBC = odbc_init() See "Connect to database" + nl see odbc_connect(pODBC,"DBQ=test.mdb;Driver={Microsoft Access Driver (*.mdb)}") + nl See "Select data" + nl see odbc_execute(pODBC,"select * from person") + nl nMax = odbc_colcount(pODBC) See "Columns Count : " + nMax + nl while odbc_fetch(pODBC) See "Row data:" + nl for x = 1 to nMax see odbc_getdata(pODBC,x) + " - " (continues on next page) 26.10. odbc_execute() Function 161
201.
Ring Documentation, Release1.16 (continued from previous page) next end See "Close database..." + nl odbc_disconnect(pODBC) odbc_close(pODBC) 26.15 odbc_tables() Function We can get a list of tables inside the database using the odbc_tables() function. We can access the result of this function as we get any query result. Syntax: odbc_tables(ODBC Handle) Example: See "ODBC test - Get Database Tables" + nl pODBC = odbc_init() See "Connect to database" + nl odbc_connect(pODBC,"DBQ=test.mdb;Driver={Microsoft Access Driver (*.mdb)}") + nl See "Select data" + nl odbc_tables(pODBC) + nl nMax = odbc_colcount(pODBC) See "Columns Count : " + nMax + nl while odbc_fetch(pODBC) for x = 1 to nMax see odbc_getdata(pODBC,x) if x != nMax see " - " ok next See nl end See "Close database..." odbc_disconnect(pODBC) odbc_close(pODBC) Output: ODBC test - Get Database Tables Connect to database Select data Columns Count : 5 .test - NULL - Customer - TABLE - NULL .test - NULL - employee - TABLE - NULL .test - NULL - person - TABLE - NULL .test - NULL - tel - TABLE - NULL Close database... 26.15. odbc_tables() Function 162
202.
Ring Documentation, Release1.16 26.16 odbc_columns() Function We can get a list of columns inside the table using the odbc_columns() function. Syntax: odbc_columns(ODBC Handle, cTableName) Example: See "ODBC test - Get Table Columns" + nl pODBC = odbc_init() See "Connect to database" + nl odbc_connect(pODBC,"DBQ=test.mdb;Driver={Microsoft Access Driver (*.mdb)}") + nl See "Get Columns inside the Person Table" + nl odbc_columns(pODBC,"person") + nl while odbc_fetch(pODBC) see odbc_getdata(pODBC,4) + nl end See "Close database..." + nl odbc_disconnect(pODBC) odbc_close(pODBC) Output: ODBC test - Get Table Columns Connect to database Get Columns inside the Person Table FIRST LAST STREET CITY STATE ZIP HIREDATE MARRIED AGE SALARY NOTES Close database... 26.17 odbc_autocommit() Function We can enable or disable the auto commit feature using the odbc_autocommit() function. Syntax: odbc_autocommit(ODBC Handle, lStatus) # lStatus can be True or False 26.16. odbc_columns() Function 163
203.
Ring Documentation, Release1.16 26.18 odbc_commit() Function We can commit updates to the database using the odbc_commit() function. Syntax: odbc_commit(ODBC Handle) 26.19 odbc_rollback() Function We can rollback updates to the database using the odbc_rollback() function. Syntax: odbc_rollback(ODBC Handle) 26.20 Transactions and Using Commit and Rollback Example: See "ODBC Test - Transactions and using Commit and Rollback" + nl pODBC = odbc_init() See "Connect to database" + nl see odbc_connect(pODBC,"DBQ=test.mdb;Driver={Microsoft Access Driver (*.mdb)}") + nl see "insert data..." + nl odbc_autocommit(pODBC,0) for x = 1 to 10000 odbc_execute(pODBC,"insert into tel values (" + x + ",'mahmoud')") next for x = 10001 to 15000 odbc_execute(pODBC,"insert into tel values (" + x + ",'samir')") next odbc_commit(pODBC) for x = 15001 to 20000 odbc_execute(pODBC,"insert into tel values (" + x + ",'fayed')") next ODBC_ROLLBACK(pODBC) odbc_execute(pODBC,"insert into tel values (" + x + ",'fayed')") odbc_commit(pODBC) See "Close database..." + nl odbc_disconnect(pODBC) odbc_close(pODBC) Output: ODBC Test - Transactions and using Commit and Rollback Connect to database 1 insert data... Close database... 26.18. odbc_commit() Function 164
204.
Ring Documentation, Release1.16 26.21 Save and Restore images The next example save an image inside the database See "ODBC test - Save image in the database" + nl pODBC = odbc_init() See "Connect to database" + nl see odbc_connect(pODBC,"DBQ=test.mdb;Driver={Microsoft Access Driver (*.mdb)}") + nl see "Read Image File..." + nl cFile = str2hex(read("testsmahmoud.jpg")) see "size " + len(CFile)+nl see "Save image in the database..." + nl stmt = "insert into tel values (20000,'mahmoud','" + cFile + "');" odbc_execute(pODBC,stmt) See "Close database..." + nl odbc_disconnect(pODBC) odbc_close(pODBC) The next example restore the image from the database See "ODBC Test - Restore image from the database" + nl pODBC = odbc_init() See "Connect to database" + nl see odbc_connect(pODBC,"DBQ=test.mdb;Driver={Microsoft Access Driver (*.mdb)}") + nl See "Select data" + nl see odbc_execute(pODBC,"select * from tel where id = 20000") + nl nMax = odbc_colcount(pODBC) See "Columns Count : " + nMax + nl if odbc_fetch(pODBC) See "Write image file" + nl write("testsgreat.jpg",hex2str( odbc_getdata(pODBC,3) ) ) ok See "Close database..." + nl odbc_disconnect(pODBC) odbc_close(pODBC) 26.21. Save and Restore images 165
205.
CHAPTER TWENTYSEVEN MYSQL FUNCTIONS In thischapter we are going to learn about the MySQL functions provided by the Ring programming language. • MySQL_Info() • MySQL_Init() • MySQL_Error() • MySQL_Connect() • MySQL_Close() • MySQL_Query() • MySQL_Insert_ID() • MySQL_Result() • MySQL_Next_Result() • MySQL_Columns() • MySQL_Result2() • MySQL_Escape_String() • MySQL_AutoCommit() • MySQL_Commit() • MySQL_Rollback() Before using the next function load the mysqllib.ring library load "mysqllib.ring" # Use MySQL functions 27.1 MySQL_Info() Function We can get the MySQL Client version using the MySQL_Info() function. Syntax: MySQL_Info() ---> string contains the MySQL Client version Example: 166
206.
Ring Documentation, Release1.16 see "MySQL Client Version : " + mysql_info() Output: MySQL Client Version : 6.1.5 27.2 MySQL_Init() Function We can start using MySQL Client through the MySQL_Init() function. Syntax: MySQL_Init() ---> MySQL Handle 27.3 MySQL_Error() Function We can get the error message from the MySQL Client using the MySQL_Error() function. Syntax: MySQL_Error(MySQL Handle) ---> Error message as string 27.4 MySQL_Connect() Function We can connect to the MySQL database server using the MySQL_Connect() function. Syntax: MySQL_Connect(MySQL Handle, cServer, cUserName, cPassword) ---> lStatus 27.5 MySQL_Close() Function We can close the connection to the MySQL database using the MySQL_Close() function Syntax: MySQL_Close(MySQL Handle) 27.2. MySQL_Init() Function 167
207.
Ring Documentation, Release1.16 27.6 MySQL_Query() Function We can execute SQL queries using the MySQL_Query() function Syntax: MySQL_Query(MySQL Handle, cSQLQuery) 27.7 Create Database The next example connect to MySQL Server then create new database. See "MySQL Test - Create Database" + nl con = mysql_init() See "Connect" + nl if mysql_connect(con,"localhost","root","root") = 0 see "Can't connect" + nl see "Error : " + mysql_error(con) + nl mysql_close(con) bye ok See "Create Database..." + nl mysql_query(con,"CREATE DATABASE mahdb") See "Close Connection" + nl mysql_close(con) Output: MySQL Test - Create Database Connect Create Database... Close Connection 27.8 Create Table and Insert Data The next example create new table and insert records func main see "Create Table and Insert Records" + nl con = mysql_init() see "Connect" + nl if mysql_connect(con, "localhost", "root", "root","mahdb") = 0 system_error(con) ok see "Drop table" + nl if mysql_query(con, "DROP TABLE IF EXISTS Employee") system_error(con) ok (continues on next page) 27.6. MySQL_Query() Function 168
208.
Ring Documentation, Release1.16 (continued from previous page) see "Create table" + nl if mysql_query(con, "CREATE TABLE Employee(Id INT, Name TEXT, Salary INT)") system_error(con) ok see "Insert data" + nl if mysql_query(con, "INSERT INTO Employee VALUES(1,'Mahmoud',15000)") system_error(con) ok if mysql_query(con, "INSERT INTO Employee VALUES(2,'Samir',16000)") system_error(con) ok if mysql_query(con, "INSERT INTO Employee VALUES(3,'Fayed',17000)") system_error(con) ok see "Close connection" + nl mysql_close(con) func system_error con see mysql_error(con) mysql_close(con) bye Output: Create Table and Insert Records Connect Drop table Create table Insert data Close connection 27.9 MySQL_Insert_ID() Function We can get the inserted row id using the MySQL_Insert_ID() function Syntax: MySQL_Insert_ID() ---> Inserted row id as number Example: con = mysql_init() see "connect to database" + nl mysql_connect(con,"localhost","root","root","mahdb") see "drop table" + nl mysql_query(con, "DROP TABLE IF EXISTS Customers") see "create table" + nl mysql_query(con, "CREATE TABLE Customers(Id INT PRIMARY KEY AUTO_INCREMENT, Name TEXT) ˓ →") see "insert record" + nl mysql_query(con, "INSERT INTO Customers(Name) VALUES('Mahmoud')") see "insert record" + nl mysql_query(con, "INSERT INTO Customers(Name) VALUES('Samir')") see "insert record" + nl mysql_query(con, "INSERT INTO Customers(Name) VALUES('Fayed')") see "insert record" + nl (continues on next page) 27.9. MySQL_Insert_ID() Function 169
209.
Ring Documentation, Release1.16 (continued from previous page) mysql_query(con, "INSERT INTO Customers(Name) VALUES('Test 2015')") see "inserted row id : " + mysql_insert_id(con) + nl see "close database" + nl mysql_close(con) Output: connect to database drop table create table insert record insert record insert record insert record inserted row id : 4 close database 27.10 MySQL_Result() Function We can get the query result (data without column names) using the MySQL_Result() function. Syntax: MySQL_Result(MySQL Handle) ---> List contains the query result 27.11 MySQL_Next_Result() Function We can move to the next query result using the MySQL_Next_Result() function. We use this function when we have multiple SQL statements in the same query. Syntax: MySQL_Next_Result(MySQL Handle) 27.12 Print Query Result The next example execute a query on the database then print the result. con = mysql_init() see "Connect to database" + nl mysql_connect(con, "localhost", "root", "root","mahdb") see "Execute Query" + nl mysql_query(con, "SELECT Name FROM Employee WHERE Id=1;"+ "SELECT Name FROM Employee WHERE Id=3") see "Print Result" + nl see mysql_result(con) mysql_next_result(con) see mysql_result(con) (continues on next page) 27.10. MySQL_Result() Function 170
210.
Ring Documentation, Release1.16 (continued from previous page) see "close database" + nl mysql_close(con) Output: Connect to database Execute Query Print Result Mahmoud Fayed close database 27.13 MySQL_Columns() Function We can get a list of columns names using the MySQL_Columns() function. Syntax: MySQL_Columns(MySQL Handle) ---> List contains columns information Example: con = mysql_init() see "Connect to database" + nl mysql_connect(con, "localhost", "root", "root","mahdb") see "Execute Query" + nl mysql_query(con, "SELECT * FROM Employee") see "Result" + nl see mysql_columns(con) see "Close database" + nl mysql_close(con) Output: Connect to database Execute Query Result Id 11 3 32768 Name 65535 252 16 Salary 11 3 32768 Close database 27.13. MySQL_Columns() Function 171
211.
Ring Documentation, Release1.16 27.14 MySQL_Result2() Function Instead of using MySQL_Result() to get the result data without columns names, we can use the MySQL_Result2() to get all of the column names then the query result in one list. Syntax: MySQL_Result2(MySQL Handle) ---> List (query result starts with columns names) Example: con = mysql_init() see "Connect to database" + nl mysql_connect(con, "localhost", "root", "root","mahdb") see "Execute Query" + nl mysql_query(con, "SELECT * FROM Employee") see "Print Result" + nl see mysql_result2(con) see "Close database" + nl mysql_close(con) Output: Connect to database Execute Query Print Result Id Name Salary 1 Mahmoud 15000 2 Samir 16000 3 Fayed 17000 Close database 27.15 MySQL_Escape_String() Function We can store binary data and special characters in the database after processing using MySQL_Escape_String() func- tion Syntax: MySQL_Escape_String(MySQL Handle, cString) ---> String after processing 27.14. MySQL_Result2() Function 172
212.
Ring Documentation, Release1.16 27.16 Save Image inside the database Example: See "Read file" + nl cFile = read("testsmahmoud.jpg") con = mysql_init() See "Connect to database..." + nl mysql_connect(con, "localhost", "root", "root","mahdb") See "Escape string..." + nl cFile = mysql_escape_string(con,cFile) stmt = "INSERT INTO photo(id, data) VALUES(1, '" + cFile + "')" See "Insert data..." + nl mysql_query(con,stmt) See "Close database..." + nl mysql_close(con) Output: Read file Connect to database... Escape string... Insert data... Close database... 27.17 Restore Image From The Database Example: con = mysql_init() See "Connect to database..." + nl mysql_connect(con, "localhost", "root", "root","mahdb") See "Read data from database..." + nl mysql_query(con,"SELECT data FROM photo WHERE id=1") See "Write new file" + nl result = mysql_result(con) write("testsmahmoud2.jpg",result[1][1]) See "Close database..." + nl mysql_close(con) Output: Connect to database... Read data from database... Write new file Close database... 27.16. Save Image inside the database 173
213.
Ring Documentation, Release1.16 27.18 MySQL_AutoCommit() Function We can enable or disable the auto commit feature using the MySQL_AutoCommit() function. Syntax: MySQL_AutoCommit(MySQL Handle, lStatus) # lstatus can be True/False 27.19 MySQL_Commit() Function We can commit updates to the database using the MySQL_Commit() function. Syntax: MySQL_Commit(MySQL Handle) 27.20 MySQL_Rollback() Function We can rollback updates to the database using the MySQL_Rollback() function. Syntax: MySQL_Rollback(MySQL Handle) 27.21 Transaction Example The next example presents the usage of MySQL_Autocommit(), MySQL_Commit() & MySQL_RollBack() functions. Example: func main con = mysql_init() see "Connect" + nl if mysql_connect(con, "localhost", "root", "root","mahdb") = 0 system_error(con) ok see "Drop table" + nl if mysql_query(con, "DROP TABLE IF EXISTS Employee2") system_error(con) ok see "Create table" + nl if mysql_query(con, "CREATE TABLE Employee2(Id INT, Name TEXT, Salary INT)") system_error(con) ok see "Insert data" + nl if mysql_query(con, "INSERT INTO Employee2 VALUES(1,'Mahmoud',15000)") system_error(con) ok if mysql_query(con, "INSERT INTO Employee2 VALUES(2,'Samir',16000)") (continues on next page) 27.18. MySQL_AutoCommit() Function 174
214.
Ring Documentation, Release1.16 (continued from previous page) system_error(con) ok if mysql_query(con, "INSERT INTO Employee2 VALUES(3,'Fayed',17000)") system_error(con) ok mysql_autocommit(con,False) mysql_query(con, "INSERT INTO Employee2 VALUES(4,'Ahmed',5000)") mysql_query(con, "INSERT INTO Employee2 VALUES(5,'Ibrahim',50000)") mysql_query(con, "INSERT INTO Employee2 VALUES(6,'Mohammed',50000)") See "Save transaction (y/n) " give nChoice if upper(nChoice) = "Y" mysql_commit(con) else mysql_rollback(con) ok see "Close connection" + nl mysql_close(con) func system_error con see mysql_error(con) mysql_close(con) bye Output: Connect Drop table Create table Insert data Save transaction (y/n) y Close connection 27.21. Transaction Example 175
215.
CHAPTER TWENTYEIGHT SQLITE FUNCTIONS In thischapter we will learn about using the SQLite database in the Ring programming language. Before using the next function load the sqlitelib.ring library load "sqlitelib.ring" # Use SQLite functions 28.1 sqlite_init() function Syntax: sqlite_init() ---> SQLite Object 28.2 sqlite_open() function Syntax: sqlite_open(SQLite Object,cFileName) 28.3 sqlite_execute() function Syntax: sqlite_execute(SQLite Object,cSQLStatement) 28.4 sqlite_close() function Syntax: sqlite_close(SQLite Object) 176
216.
Ring Documentation, Release1.16 28.5 Example The next code create a SQLite database, add new records then display the data. load "sqlitelib.ring" oSQLite = sqlite_init() sqlite_open(oSQLite,"mytest.db") sql = " CREATE TABLE COMPANY ( ID INT PRIMARY KEY NOT NULL, NAME TEXT NOT NULL, AGE INT NOT NULL, ADDRESS CHAR(50), SALARY REAL ); " sqlite_execute(oSQLite,sql) sql = " INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES (1, 'Mahmoud' , 29, 'Jeddah', 20000.00 ), (2, 'Ahmed' , 27, 'Jeddah', 15000.00 ), (3, 'Mohammed', 31, 'Egypt' , 20000.00 ), (4, 'Ibrahim' , 24, 'Egypt ', 65000.00 ); " sqlite_execute(oSQLite,sql) aResult = sqlite_execute(oSQLite,"select * from COMPANY") for x in aResult for t in x ? t[2] + nl next next ? copy("*",50) for x in aResult ? x[:name] next sqlite_close(oSQLite) Output: 1 Mahmoud 29 Jeddah 20000.0 2 Ahmed 27 Jeddah 15000.0 3 Mohammed 31 (continues on next page) 28.5. Example 177
217.
Ring Documentation, Release1.16 (continued from previous page) Egypt 20000.0 4 Ibrahim 24 Egypt 65000.0 ************************************************** Mahmoud Ahmed Mohammed Ibrahim 28.5. Example 178
218.
CHAPTER TWENTYNINE POSTGRESQL FUNCTIONS In thischapter we will learn about using the PostgreSQL database in the Ring programming language. 29.1 Loading the library Before using the next function load the postgresqllib.ring library load "postgresqllib.ring" # Use PostgreSQL functions 29.2 Examples Example (1): load "postgresqllib.ring" conninfo = "user=postgres password=sa dbname = postgres" exit_nicely = func conn { PQfinish(conn) shutdown(1) } conn = PQconnectdb(conninfo) if (PQstatus(conn) != CONNECTION_OK) fputs(stderr, "Connection to database failed: "+PQerrorMessage(conn)) call exit_nicely(conn) ok res = PQexec(conn, "select * from pg_database") if PQresultStatus(res) != PGRES_TUPLES_OK fputs(stderr, "Select failed: " + PQerrorMessage(conn)) PQclear(res) exit_nicely(conn) ok nFields = PQnfields(res) for i = 1 to nFields ? PQfname(res, i-1) (continues on next page) 179
219.
Ring Documentation, Release1.16 (continued from previous page) next ? copy("*",60) for i = 1 to PQntuples(res) for j=1 to nFields see PQgetvalue(res, i-1, j-1) + " " next see nl next PQclear(res) PQfinish(conn) Output: datname datdba encoding datcollate datctype datistemplate datallowconn datconnlimit datlastsysoid datfrozenxid datminmxid dattablespace datacl ************************************************************ postgres 10 6 English_United States.1252 English_United States.1252 f t -1 12937 549 1 1663 template1 10 6 English_United States.1252 English_United States.1252 t t -1 12937 549 1 1663 {=c/postgres,postgres=CTc/postgres} template0 10 6 English_United States.1252 English_United States.1252 t f -1 12937 549 1 1663 {=c/postgres,postgres=CTc/postgres} mahdb 10 6 English_United States.1252 English_United States.1252 f t -1 12937 549 1 1663 Example(2): load "postgresqllib.ring" conninfo = "user=postgres password=sa dbname = mahdb" exit_nicely = func conn { PQfinish(conn) shutdown(1) } conn = PQconnectdb(conninfo) if (PQstatus(conn) != CONNECTION_OK) fputs(stderr, "Connection to database failed: "+PQerrorMessage(conn)) call exit_nicely(conn) ok (continues on next page) 29.2. Examples 180
220.
Ring Documentation, Release1.16 (continued from previous page) res = PQexec(conn, " DROP DATABASE mahdb; ") if PQresultStatus(res) != PGRES_TUPLES_OK fputs(stderr, "Remove failed: " + PQerrorMessage(conn)) PQclear(res) ok PQclear(res) res = PQexec(conn, "CREATE DATABASE mahdb;") if PQresultStatus(res) != PGRES_TUPLES_OK fputs(stderr, "Create database failed: " + PQerrorMessage(conn)) PQclear(res) ok res = PQexec(conn, " CREATE TABLE COMPANY ( ID INT PRIMARY KEY NOT NULL, NAME TEXT NOT NULL, AGE INT NOT NULL, ADDRESS CHAR(50), SALARY REAL ); ") if PQresultStatus(res) != PGRES_TUPLES_OK fputs(stderr, "Create Table failed: " + PQerrorMessage(conn)) PQclear(res) ok PQclear(res) res = PQexec(conn, " INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES (1, 'Mahmoud' , 31, 'Jeddah', 10.00 ), (2, 'Ahmed' , 27, 'Jeddah', 20.00 ), (3, 'Mohammed', 33, 'Egypt' , 30.00 ), (4, 'Ibrahim' , 24, 'Egypt ', 40.00 ); ") if PQresultStatus(res) != PGRES_TUPLES_OK fputs(stderr, "Insert Table failed: " + PQerrorMessage(conn)) PQclear(res) ok PQclear(res) res = PQexec(conn, " select * from COMPANY ") if PQresultStatus(res) != PGRES_TUPLES_OK fputs(stderr, "Select failed: " + PQerrorMessage(conn)) PQclear(res) call exit_nicely(conn) ok nFields = PQnfields(res) for i = 1 to nFields (continues on next page) 29.2. Examples 181
221.
Ring Documentation, Release1.16 (continued from previous page) ? PQfname(res, i-1) next ? copy("*",60) for i = 1 to PQntuples(res) for j=1 to nFields see PQgetvalue(res, i-1, j-1) + " " next see nl next PQclear(res) PQfinish(conn) Output: id name age address salary ************************************************************ 1 Mahmoud 31 Jeddah 10 2 Ahmed 27 Jeddah 20 3 Mohammed 31 Egypt 30 4 Ibrahim 24 Egypt 40 29.3 RingPostgreSQL Constants The next constants are define by the RingPostgreSQL Library CONNECTION_STARTED CONNECTION_MADE CONNECTION_AWAITING_RESPONSE CONNECTION_AUTH_OK CONNECTION_SSL_STARTUP CONNECTION_SETENV CONNECTION_OK PQPING_OK PQPING_REJECT PQPING_NO_RESPONSE PQPING_NO_ATTEMPT PGRES_EMPTY_QUERY PGRES_COMMAND_OK PGRES_TUPLES_OK PGRES_COPY_OUT PGRES_COPY_IN PGRES_BAD_RESPONSE PGRES_NONFATAL_ERROR PGRES_FATAL_ERROR (continues on next page) 29.3. RingPostgreSQL Constants 182
Ring Documentation, Release1.16 (continued from previous page) char *PQtty(const PGconn *conn) char *PQoptions(const PGconn *conn) ConnStatusType PQstatus(const PGconn *conn) PGTransactionStatusType PQtransactionStatus(const PGconn *conn) const char *PQparameterStatus(const PGconn *conn, const char *paramName) int PQprotocolVersion(const PGconn *conn) int PQserverVersion(const PGconn *conn) char *PQerrorMessage(const PGconn *conn) int PQsocket(const PGconn *conn) int PQbackendPID(const PGconn *conn) int PQconnectionNeedsPassword(const PGconn *conn) int PQconnectionUsedPassword(const PGconn *conn) int PQsslInUse(const PGconn *conn) const char *PQsslAttribute(const PGconn *conn, const char *attribute_name) const char **PQsslAttributeNames(const PGconn *conn) void *PQsslStruct(const PGconn *conn, const char *struct_name) void *PQgetssl(const PGconn *conn) PGresult *PQexec(PGconn *conn, const char *command); PGresult *PQexecParams(PGconn *conn,const char *command,int nParams, const Oid *paramTypes,const char **paramValues, const int *paramLengths,const int *paramFormats,int resultFormat) PGresult *PQprepare(PGconn *conn,const char *stmtName, const char *query,int nParams,const Oid *paramTypes) PGresult *PQexecPrepared(PGconn *conn,const char *stmtName, int nParams,const char **paramValues, const int *paramLengths,const int *paramFormats,int resultFormat) PGresult *PQdescribePrepared(PGconn *conn, const char *stmtName) PGresult *PQdescribePortal(PGconn *conn, const char *portalName) ExecStatusType PQresultStatus(const PGresult *res) char *PQresStatus(ExecStatusType status) char *PQresultErrorMessage(const PGresult *res) char *PQresultErrorField(const PGresult *res, int fieldcode) void PQclear(PGresult *res) int PQntuples(const PGresult *res) int PQnfields(const PGresult *res) char *PQfname(const PGresult *res,int column_number) int PQfnumber(const PGresult *res,const char *column_name) Oid PQftable(const PGresult *res,int column_number) int PQftablecol(const PGresult *res,int column_number) int PQfformat(const PGresult *res,int column_number) Oid PQftype(const PGresult *res,int column_number) int PQfmod(const PGresult *res,int column_number) int PQfsize(const PGresult *res,int column_number) int PQbinaryTuples(const PGresult *res) char *PQgetvalue(const PGresult *res,int row_number,int column_number) int PQgetisnull(const PGresult *res,int row_number,int column_number) int PQgetlength(const PGresult *res,int row_number,int column_number) int PQnparams(const PGresult *res) Oid PQparamtype(const PGresult *res, int param_number) void PQprint(FILE *fout,const PGresult *res,const PQprintOpt *po) char *PQcmdStatus(PGresult *res) char *PQcmdTuples(PGresult *res) Oid PQoidValue(const PGresult *res) char *PQoidStatus(const PGresult *res) char *PQescapeLiteral(PGconn *conn, const char *str, size_t length) char *PQescapeIdentifier(PGconn *conn, const char *str, size_t length) size_t PQescapeStringConn(PGconn *conn,char *to, (continues on next page) 29.4. RingPostgreSQL Functions 184
224.
Ring Documentation, Release1.16 (continued from previous page) const char *from, size_t length,int *error) size_t PQescapeString(char *to, const char *from, size_t length) unsigned char *PQescapeByteaConn(PGconn *conn, const unsigned char *from,size_t from_length,size_t *to_length) unsigned char *PQescapeBytea(const unsigned char *from, size_t from_length,size_t *to_length) unsigned char *PQunescapeBytea(const unsigned char *from, size_t *to_length) int PQsendQuery(PGconn *conn, const char *command) int PQsendQueryParams(PGconn *conn,const char *command, int nParams,const Oid *paramTypes,const char **paramValues, const int *paramLengths,const int *paramFormats,int resultFormat) int PQsendPrepare(PGconn *conn,const char *stmtName, const char *query,int nParams,const Oid *paramTypes) int PQsendQueryPrepared(PGconn *conn,const char *stmtName, int nParams,const char **paramValues, const int *paramLengths,const int *paramFormats,int resultFormat) int PQsendDescribePrepared(PGconn *conn, const char *stmtName) int PQsendDescribePortal(PGconn *conn, const char *portalName) PGresult *PQgetResult(PGconn *conn) int PQconsumeInput(PGconn *conn) int PQisBusy(PGconn *conn) int PQsetnonblocking(PGconn *conn, int arg) int PQisnonblocking(const PGconn *conn) int PQflush(PGconn *conn) int PQsetSingleRowMode(PGconn *conn) PGcancel *PQgetCancel(PGconn *conn) void PQfreeCancel(PGcancel *cancel) int PQcancel(PGcancel *cancel, char *errbuf, int errbufsize) int PQrequestCancel(PGconn *conn) PGresult *PQfn(PGconn *conn,int fnid,int *result_buf, int *result_len,int result_is_int,const PQArgBlock *args,int nargs) PGnotify *PQnotifies(PGconn *conn) int PQputCopyData(PGconn *conn,const char *buffer,int nbytes) int PQputCopyEnd(PGconn *conn,const char *errormsg) int PQgetCopyData(PGconn *conn,char **buffer,int async) int PQgetline(PGconn *conn,char *buffer,int length) int PQgetlineAsync(PGconn *conn,char *buffer,int bufsize) int PQputline(PGconn *conn,const char *string) int PQputnbytes(PGconn *conn,const char *buffer,int nbytes) int PQendcopy(PGconn *conn) int PQclientEncoding(const PGconn *conn) char *pg_encoding_to_char(int encoding_id) int PQsetClientEncoding(PGconn *conn, const char *encoding) void PQtrace(PGconn *conn, FILE *stream) void PQuntrace(PGconn *conn) void PQfreemem(void *ptr) void PQconninfoFree(PQconninfoOption *connOptions) char *PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, const char *algorithm) char *PQencryptPassword(const char *passwd, const char *user) PGresult *PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status) int PQfireResultCreateEvents(PGconn *conn, PGresult *res) PGresult *PQcopyResult(const PGresult *src, int flags) int PQsetResultAttrs(PGresult *res, int numAttributes, PGresAttDesc *attDescs) int PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len) void *PQresultAlloc(PGresult *res, size_t nBytes) (continues on next page) 29.4. RingPostgreSQL Functions 185
225.
Ring Documentation, Release1.16 (continued from previous page) int PQlibVersion(void) PQnoticeReceiver PQsetNoticeReceiver(PGconn *conn, PQnoticeReceiver proc,void *arg) PQnoticeProcessor PQsetNoticeProcessor(PGconn *conn, PQnoticeProcessor proc,void *arg) void PQinitOpenSSL(int do_ssl, int do_crypto) void PQinitSSL(int do_ssl) int PQisthreadsafe(void) 29.4. RingPostgreSQL Functions 186
226.
CHAPTER THIRTY SECURITY AND INTERNETFUNCTIONS This chapter contains the security and internet functions provided by the Ring programming language for Hashing, Encryption & Decryption. Before using the next functions load the openssllib.ring library load "openssllib.ring" # Use OpenSSL functions • MD5() • SHA1() • SHA256() • SHA512() • SHA384() • SHA224() • Encrypt() • Decrypt() • Randbytes() • MD5Init(), MD5Update(), MD5Final() • SHA1Init(), SHA1Update(), SHA1Final() • SHA256Init(), SHA256Update(), SHA256Final() • SHA512Init(), SHA512Update(), SHA512Final() • SHA384Init(), SHA384Update(), SHA384Final() • SHA224Init(), SHA224Update(), SHA224Final() Before using the next functions load the internetlib.ring library load "internetlib.ring" # Use the Internet functions • Download() • SendEmail() 187
227.
Ring Documentation, Release1.16 30.1 MD5() Function We can calculate the MD5 hash using the MD5() Function Syntax: MD5(cString) ---> String contains the MD5 hash of the string cString Example: see "md5('happy') = " + md5("happy") + nl + "md5('Hello') = " + md5("Hello") + nl Output: md5('happy') = 56ab24c15b72a457069c5ea42fcfc640 md5('Hello') = 8b1a9953c4611296a827abf8c47804d7 30.2 SHA1() Function We can calculate the SHA1 hash using the SHA1() Function Syntax: SHA1(cString) ---> String contains the SHA1 hash of the string cString Example: see "sha1('hello') : " + sha1("hello") + nl + "sha1('apple') : " + sha1("apple") + nl Output: sha1('hello') : aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d sha1('apple') : d0be2dc421be4fcd0172e5afceea3970e2f3d940 30.3 SHA256() Function We can calculate the SHA256 hash using the SHA256() Function Syntax: SHA256(cString) ---> String contains the SHA256 hash of the string cString Example: see "sha256('hello') : " + sha256("hello") + nl + "sha256('apple') : " + sha256("apple") + nl Output: sha256('hello') : 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 sha256('apple') : 3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b 30.1. MD5() Function 188
228.
Ring Documentation, Release1.16 30.4 SHA512() Function We can calculate the SHA512 hash using the SHA512() Function Syntax: SHA512(cString) ---> String contains the SHA512 hash of the string cString Example: see "sha512('hello') : " + sha512("hello") + nl + "sha512('apple') : " + sha512("apple") + nl + "sha512('hello world') : " + sha512("hello world") + nl Output: sha512('hello') : 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673c a72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043 sha512('apple') : 844d8779103b94c18f4aa4cc0c3b4474058580a991fba85d3ca698a0bc9e52 c5940feb7a65a3a290e17e6b23ee943ecc4f73e7490327245b4fe5d5efb590feb2 sha512('hello world') : 309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca8 6d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f 30.5 SHA384() Function We can calculate the SHA384 hash using the SHA384() Function Syntax: SHA384(cString) ---> String contains the SHA384 hash of the string cString Example: see "sha384('hello') : " + sha384("hello") + nl + "sha384('apple') : " + sha384("apple") + nl + "sha384('hello world') : " + sha384("hello world") + nl Output: sha384('hello') : 59e1748777448c69de6b800d7a33bbfb9ff1b463e44354c3553bcdb9c666fa 90125a3c79f90397bdf5f6a13de828684f sha384('apple') : 3d8786fcb588c93348756c6429717dc6c374a14f7029362281a3b21dc10250 ddf0d0578052749822eb08bc0dc1e68b0f sha384('hello world') : fdbd8e75a67f29f701a4e040385e2e23986303ea10239211af907fcb b83578b3e417cb71ce646efd0819dd8c088de1bd 30.4. SHA512() Function 189
229.
Ring Documentation, Release1.16 30.6 SHA224() Function We can calculate the SHA224 hash using the SHA224() Function Syntax: SHA224(cString) ---> String contains the SHA224 hash of the string cString Example: see "sha224('hello') : " + sha224("hello") + nl + "sha224('apple') : " + sha224("apple") + nl + "sha224('hello world') : " + sha224("hello world") + nl Output: sha224('hello') : ea09ae9cc6768c50fcee903ed054556e5bfc8347907f12598aa24193 sha224('apple') : b7bbfdf1a1012999b3c466fdeb906a629caa5e3e022428d1eb702281 sha224('hello world') : 2f05477fc24bb4faefd86517156dafdecec45b8ad3cf2522a563582b 30.7 Encrypt() Function We can use the Encrypt() function to encrypts the data using the Blowfish algorithm. Syntax: Encrypt(cString, cKey, cIV) ---> Encrypted string 30.8 Decrypt() Function We can use the Decrypt() function to decrypt the data encrypted using the Encrypt() function. Syntax: Decrypt(cCipher, cKey, cIV) ---> Decrypted string 30.9 Encryption and Decryption Example The next example demonstrates how to use the Encrypt() and Decrypt() functions. These functions use the Blowfish algorithm. See "Enter a string : " give cStr list = 0:15 cKey="" for x in list cKey += char(x) next list = 1:8 cIV = "" for x in list cIV += char(x) next cStr = Encrypt(cStr,cKey,cIV) See "Cipher Text : " + cStr + nl + "Plain Text : " + Decrypt(cStr,cKey,cIV) + nl We can write the same example using normal for loop 30.6. SHA224() Function 190
230.
Ring Documentation, Release1.16 See "Enter a string : " give cStr cKey="" # 16 bytes for x = 0 to 15 cKey += char(x) next cIV = "" for x = 1 to 8 cIV += char(x) next cStr = Encrypt(cStr,cKey,cIV) See "Cipher Text : " + cStr + nl + "Plain Text : " + Decrypt(cStr,cKey,cIV) + nl Also we can write the password and the IV directly using strings See "Enter a string : " give cStr # Note: Don't use simple password in real applications! cKey = "1234567890@#$%^&" cIV = "87654321" cStr = Encrypt(cStr,cKey,cIV) See "Cipher Text : " + cStr + nl + "Plain Text : " + Decrypt(cStr,cKey,cIV) + nl 30.10 File Hash The next example demonstrates how to calculate the hash functions for files cStr = read("myapp.exe") see "Size : " + len(cStr) + nl + "md5 : " + md5(cStr) + nl + "sha1 : " + sha1(cStr) + nl + "sha256 : " + sha256(cStr) + nl + "sha224 : " + sha224(cStr) + nl + "sha384 : " + sha384(cStr) + nl + "sha512 : " + sha512(cStr) + nl Output: Size : 58079876 md5 : 762eee15d8d2fd73b71ea52538b28667 sha1 : 9212c0c7258bad89a62bd239e1358a9276a9d070 sha256 : 7d6724e69b6c553da749ba31b6185dddc965129b64d9e9bf3de88f67df3b1cdc sha224 : 5a9c8a7d662bce4f880ba94f90a79362b672528b9efd5abc718c7a3d sha384 : 18e23f973abedbeb3981c423f12aeadecf96f9c6fb28aeabe3be4c484f8540afcc3861b b370ce2b59cf3c99c130b856b sha512 : da3d5e997d06f8b2a7a9964b77f7d82eedb76b245c611082c1639f83f51d83880bcd08f cd53dcab1167bdca0b82fec5071971ac17c76479d76985ced4ab0d18e 30.10. File Hash 191
231.
Ring Documentation, Release1.16 30.11 Randbytes() Function We can generate a string of pseudo-random bytes using the Randbytes() function. Syntax: Randbytes(nSize) ---> String contains random bytes (bytes count = nSize) Example: salt = randbytes(32) password = "SecretPassWord@$%123" see salt + nl see sha256("test" + salt) + nl 30.12 Large Files Hash These functions compute the hash of large files/data without the need to load all of the content in a single string. md5init() -> MD5_CTX md5update (MD5_CTX, string) -> 1 for success or 0 for failure md5final (MD5_CTX) -> string sha1init() -> SHA_CTX sha1update (SHA_CTX, string) -> 1 for success or 0 for failure sha1final (SHA_CTX) -> string sha224init() -> SHA224_CTX sha224update (SHA224_CTX, string) -> 1 for success or 0 for failure sha224final (SHA224_CTX) -> string sha256init() -> SHA256_CTX sha256update (SHA256_CTX, string) -> 1 for success or 0 for failure sha256final (SHA256_CTX) -> string sha384init() -> SHA384_CTX sha384update (SHA384_CTX, string) -> 1 for success or 0 for failure sha384final (SHA384_CTX) -> string sha512init() -> SHA512_CTX sha512update (SHA512_CTX, string) -> 1 for success or 0 for failure sha512final (SHA512_CTX) -> string 30.13 Download() Function Syntax: Download(cURL) ---> String contains the server response Example: 30.11. Randbytes() Function 192
232.
Ring Documentation, Release1.16 cStr= download("http://doublesvsoop.sourceforge.net/") see cStr write("download.txt",cStr) 30.14 SendEmail() Function Syntax: SendEmail(cSMTPServer,cEmail,cPassword,cSender,cReceiver,cCC,cTitle,cContent) Example: See "Send email..." + nl sendemail("smtp://smtp.gmail.com:587", "email@gmail.com", "password", "email@gmail.com", "somebody@yahoo.com", "somebodyelse@yahoo.com", "Sending email from Ring", "Hello How are you? Are you fine? Thank you! Greetings, Mahmoud") see "Done.." + nl 30.14. SendEmail() Function 193
233.
CHAPTER THIRTYONE OBJECT ORIENTED PROGRAMMING(OOP) In this chapter we are going to learn how to use the Object-Oriented programming paradigm inside the Ring program- ming language. We will learn about • Classes and Objects • Access Objects Using Braces • Composition • Setter and Getter • Private Attributes and Methods • Operator Overloading • Inheritance • Dynamic Attributes • Packages • Printing Objects • Find() and List of Objects • Sort() and List of Objects • Using Self.Attribute and Self.Method() • Using This.Attribute and This.Method() 31.1 Classes and Objects We can define new classes using the next syntax Syntax: Class <Class Name> [From|<|: <Parent Class Name>] [Attributes] [Methods] [Private [Attributes] [Methods] ] 194
234.
Ring Documentation, Release1.16 And we can create objects using the next syntax Syntax: New <Object Name> [ (init method parameters) ] | [ { access object data and methods } ] ---> Object Example: New point { x=10 y=20 z=30 print() } Class Point x y z func print see x + nl + y + nl + z + nl Note: We can use { } to access object data and methods. Tip: we can declare the class attributes directly after the class name. Output: 10 20 30 We can rewrite the same program in another style New point # create new object using the point class { # access the new object attributes and methods x = 10 # set the x attribute to 10 y = 20 # set the y attribute to 20 z = 30 # set the z attribute to 30 print() # call the print method } # end of object access Class Point # define the Point class x y z # the class contains three attributes x, y & z func print # define the print method see x + nl + # print the x attribute y + nl + # print the y attribute z + nl # print the z attribute Also we can write the same program in another way P1 = New Point P1.x = 10 P1.y = 20 P1.z = 30 P1.Print() Class Point x y z func print see x + nl + y + nl + z + nl Note: we can use the dot operator after the object name to access object members. Also we can write the same program in another way 31.1. Classes and Objects 195
235.
Ring Documentation, Release1.16 new point { print() } Class Point x = 10 y = 20 z = 30 func print see x + nl + y + nl + z + nl Note: we can set the default values for the class attributes when we declare them. Also we can write the same program in another way new point(10,20,30) Class Point x y z func init p1,p2,p3 x=p1 y=p2 z=p3 print() func print see x + nl + y + nl + z + nl Note: we can call the init method directly using () when we create new objects Also we can write the same program in another way new point( [ :x = 10 , :y = 20 , :z = 30 ] ) Class Point x y z func init aPara x = aPara[:x] y = aPara[:y] z = aPara[:z] print() func print see x + nl + y + nl + z + nl Tip: using Hash for passing method parameters enable us to create optional parameters and change the order of parameters when adding them to the Hash. 31.2 Access Objects Using Braces We can access the object at any time using braces { } Inside the braces we can use the object attributes and methods directly This can be done when we create the object using the New keyword or at any time using the next syntax ObjectName { access object data and methods } Example: See "Creating the Object" + nl o1 = new Point See "Using the Object" + nl o1 { x=5 y=15 z=25 print() } Class Point x y z func print see x + nl + y + nl + z 31.2. Access Objects Using Braces 196
236.
Ring Documentation, Release1.16 We can use braces to access objects when we call functions or methods Example: o1 = new Point print( o1 { x=10 y=20 z=30 } ) func print object see object.x + nl + object.y + nl + object.z Class Point x y z We can mix between using braces and the dot operator to access the object in the same expression. Example: o1 = new Point O1 { x=10 y=20 z=30 }.print() Class Point x y z func print see x + nl + y + nl + z 31.3 Composition The object may contains other objects as attributes. Using braces to access objects can be nested. Example: R1 = New Rectangle { Name = "Rectangle 1" P1 { X = 10 Y = 20 } P2 { X = 200 Y = 300 } Color = "Blue" } see "Name : " + R1.Name + nl + "Color: " + R1.Color + nl + (continues on next page) 31.3. Composition 197
237.
Ring Documentation, Release1.16 (continued from previous page) "P1 : (" + R1.P1.X + "," + R1.P1.Y + ")" + nl + "P2 : (" + R1.P2.X + "," + R1.P2.Y + ")" Class Rectangle name color p1 = new Point p2 = new Point Class Point x y Output: Name : Rectangle 1 Color: Blue P1 : (10,20) P2 : (200,300) 31.4 Setter and Getter We can define methods to be used when we set and get object attributes. Syntax: Class ClassName AttributeName ... Func SetAttributeName ... Func GetAttributeName ... Example: o1 = new person o1.name = "Mahmoud" see o1.name + nl o1 { name = "Ahmed" see name } Class Person name family = "Fayed" func setname value see "Message from SetName() Function!" + nl name = value + " " + family func getname see "Message from GetName() Function!" + nl return "Mr. " + name Output: 31.4. Setter and Getter 198
238.
Ring Documentation, Release1.16 Message from SetName() Function! Message from GetName() Function! Mr. Mahmoud Fayed Message from SetName() Function! Message from GetName() Function! Mr. Ahmed Fayed 31.5 Private Attributes and Methods We can define private attributes and methods after the keyword private inside the class body Example: o1 = new person { name = "Test" age = 20 print() o1.printsalary() } try see o1.salary catch see cCatchError + nl done try o1.increasesalary(1000) catch see cCatchError + nl done Class Person name age func print see "Name : " + name + nl + "Age : " + age + nl func printsalary see "Salary : " + salary + nl private salary = 15000 func increasesalary x salary += x Output: Name : Test Age : 20 Salary : 15000 (continues on next page) 31.5. Private Attributes and Methods 199
239.
Ring Documentation, Release1.16 (continued from previous page) Error (R27) : Using private attribute from outside the class : salary Error (R26) : Calling private method from outside the class : increasesalary 31.6 Operator Overloading We can add the operator method to our class to enable using operators with the class objects. Syntax: Class ClassName ... Func operator cOperator,Para ... The function operator takes two parameters, the first represent the operator and the second represent the second pa- rameter after the operator. Example: o1 = new point { x = 10 y = 10 print("P1 : ") } o2 = new point { x = 20 y = 40 print("P2 : ") } o3 = o1 + o2 o3.print("P1+P2 : ") class point x y func operator cOperator,Para result = new point switch cOperator on "+" result.x = x + Para.x result.y = y + Para.y on "-" result.x = x - Para.x result.y = y - Para.y off return result func print cPoint see cPoint + "X : " + x + " Y : " + y + nl Output: P1 : X : 10 Y : 10 P2 : X : 20 Y : 40 P1+P2 : X : 30 Y : 50 The next example from the List class in the stdlib.ring Func operator cOperator,Para result = new list (continues on next page) 31.6. Operator Overloading 200
240.
Ring Documentation, Release1.16 (continued from previous page) switch cOperator on "+" if isobject(para) for t in Para.vValue vValue + t next but islist(para) for t in Para vValue + t next ok on "len" return len( vValue ) on "[]" return &vValue[para] off return result The “len” operator is used with (for in) control structure. The “[]” operator is used when we try to access the list items, In this case we use the & operator to return the item values like strings an numbers by reference, so we can update it when we access the items. Another Example func main See "----1"+nl a1 = new BigNumber( "123" ) a2 = new BigNumber( "456" ) a3 = new BigNumber( "789" ) See nl+"----2"+nl a1.print() a2.print() a3.print() See nl+"----3"+nl a2 = a1 + "45" See nl+"----4"+nl a2.print() See nl+"----5"+nl a3 = a1 + a2 See nl+"----6"+nl a3.print() See nl+"----7"+nl ###================================== Func FuncAdd( num1, num2) Sum = 0 + num1 + num2 ### Para.aData isNumber Sum = "" +Sum ### Para.adata isString return Sum ### return to Class ###=================================== class BigNumber ### Variables aData = "468" (continues on next page) 31.6. Operator Overloading 201
241.
Ring Documentation, Release1.16 (continued from previous page) ### Functions INIT default values func init aPara ? "INIT aPara: " ? aPara if isString(aPara) aData = aPara else aData = "" + aPara ok ### Other Functions func operator cOperator, Para whatType = Type(Para) ? nl+"WhatType-PARA: "+ whatType ? Para ? nl+"Operator: " ? cOperator ? nl+"PARA: " ? Para ? " ______" ? nl if whatType = "STRING" dataInfo = Para ? "dataInfo String: " ? dataInfo but whatType = "NUMBER" datinfo = "" + Para ? "dataInfo Number: " ? dataInfo else whatType = "OBJECT" dataInfo = "" + para.aData ? "dataInfo OBJECT: " ? dataInfo ok ? "dataInfo USING: " ? dataInfo ### Para.aData does NOT exist on first pass ( Object with member) ### Result isObject when assigned "self" result = self switch cOperator on "+" answer = FuncAdd( aData, dataInfo ) ? nl+"AnswerString - FunAdd aData, dataInfo: " ? answer ### result = self, is Object, populate Object with aData member result.aData = answer off ### Result = Self is Object return result func print ? nl+"ClassPrint aData: " ? aData 31.7 Inheritance We can create class from another class in the class definition using the keyword from. Syntax: Class <Class Name> [From <Parent Class Name>] We can call a method in the parent class from the child class using the super object. Syntax: func methodname ... (continues on next page) 31.7. Inheritance 202
242.
Ring Documentation, Release1.16 (continued from previous page) super.methodname() ... Example: Func main e1 = new Employee { Name = "test" age = 20 job = "programmer" salary = 20000000 print() } Class Human Name Age func print see "Name : " + name + nl + "Age : " + age + nl Class Employee from Human Job Salary func print super.print() see "Job : " + job + nl + "Salary : " + salary + nl Output: Name : test Age : 20 Job : programmer Salary : 20000000 31.8 Dynamic Attributes We can write instructions after the class name to be executed when we create new objects Example: o1 = new dynamicClass see o1.var5 + nl # output 5 Class DynamicClass for x = 1 to 10 cStr = "var" + x + " = " + x eval(cStr) next Tip: in the previous example var1, var2, ..., var10 will be defined as attributes. Tip: The problem with the previous example is that x and cStr will be defined as attributes too! 31.8. Dynamic Attributes 203
243.
Ring Documentation, Release1.16 Note: we can write class definitions inside a string then using eval() we can execute the string to define the classes 31.9 Packages We can create a package (a group of classes under a common name) using the next syntax package PackageName Class Class1 ... Class Class2 ... Class Class3 ... ... Example o1 = new System.output.console o1.print("Hello World") Package System.Output Class Console Func Print cText see cText + nl Note: we can use the dot operator as part of the package name Instead of typing the long name PackageName.ClassName we can use the import command When we import a package, we can use any class inside this package directly. Example import system.output o1 = new console { print("Hello World") } Package System.Output Class Console Func Print cText see cText + nl 31.9. Packages 204
244.
Ring Documentation, Release1.16 31.10 Printing Objects We can print the object state (attributes and values) using the see command. Example: see new point { x=10 y=20 z=30 } class point x y z Output: x: 10.000000 y: 20.000000 z: 30.000000 31.11 Find() and List of Objects We can use the find() function to search inside a list of objects. Syntax: Find(List,ItemValue,nColumn,cAttribute) ---> Item Index Example: myList1 = [new Company {position=3 name="Mahmoud" symbol="MHD"}, new Company {position=2 name="Bert" symbol="BRT"}, new Company {position=1 name="Ring" symbol="RNG"} ] see find(mylist1,"Bert",1,"name") + nl see find(mylist1,"Ring",1,"name") + nl see find(mylist1,"Mahmoud",1,"name") + nl see find(mylist1,"RNG",1,"symbol") + nl see find(mylist1,"MHD",1,"symbol") + nl see find(mylist1,"BRT",1,"symbol") + nl see find(mylist1,3,1,"position") + nl see find(mylist1,1,1,"position") + nl see "Other" + nl see find(mylist1,"test",1,"name") + nl see find(mylist1,"test",0,"name") + nl see find(mylist1,"test",5,"name") + nl class company position name symbol Output: 2 3 1 3 1 2 1 3 (continues on next page) 31.10. Printing Objects 205
245.
Ring Documentation, Release1.16 (continued from previous page) Other 0 0 0 31.12 Sort() and List of Objects We can sort a list of objects based on an object attribute using the Sort() function. Syntax: Sort(List,nColumn,cAttribute) ---> Sorted List based on Object Attribute Example: myList1 = [ new Company {position=3 name="Mahmoud" symbol="MHD"}, new Company {position=2 name="Bert" symbol="BRT"}, new Company {position=8 name="Charlie" symbol="CHR"}, new Company {position=6 name="Easy" symbol="FEAS"}, new Company {position=7 name="Fox" symbol="EFOX"}, new Company {position=5 name="Dog" symbol="GDOG"}, new Company {position=4 name="George" symbol="DGRG"}, new Company {position=1 name="Ring" symbol="RNG"} ] see sort(mylist1,1,"name") see copy("*",70) + nl see sort(mylist1,1,"symbol") see copy("*",70) + nl see sort(mylist1,1,"position") class company position name symbol Output: position: 2.000000 name: Bert symbol: BRT position: 8.000000 name: Charlie symbol: CHR position: 5.000000 name: Dog symbol: GDOG position: 6.000000 name: Easy symbol: FEAS position: 7.000000 name: Fox symbol: EFOX position: 4.000000 name: George symbol: DGRG (continues on next page) 31.12. Sort() and List of Objects 206
246.
Ring Documentation, Release1.16 (continued from previous page) position: 3.000000 name: Mahmoud symbol: MHD position: 1.000000 name: Ring symbol: RNG ********************************************************************** position: 2.000000 name: Bert symbol: BRT position: 8.000000 name: Charlie symbol: CHR position: 4.000000 name: George symbol: DGRG position: 7.000000 name: Fox symbol: EFOX position: 6.000000 name: Easy symbol: FEAS position: 5.000000 name: Dog symbol: GDOG position: 3.000000 name: Mahmoud symbol: MHD position: 1.000000 name: Ring symbol: RNG ********************************************************************** position: 1.000000 name: Ring symbol: RNG position: 2.000000 name: Bert symbol: BRT position: 3.000000 name: Mahmoud symbol: MHD position: 4.000000 name: George symbol: DGRG position: 5.000000 name: Dog symbol: GDOG position: 6.000000 name: Easy symbol: FEAS position: 7.000000 name: Fox symbol: EFOX position: 8.000000 name: Charlie symbol: CHR 31.12. Sort() and List of Objects 207
247.
Ring Documentation, Release1.16 31.13 Using Self.Attribute and Self.Method() Inside the class region (After the class name and before any method) and the class methods we can use self.attribute and self.method() Class Point self.x = 10 self.y = 20 self.z = 30 func print see self.x + nl + self.y + nl + self.z + nl Note: using self.attribute in the class region to define the class attribute protect the class attributes from conflict with global variables. Tip: if you typed the class attributes with self.attribute and there are a global variable with the same name it will be used and the attribute will not be defined. Check the “Scope Rules” chapter to know about the conflict between the global variable name and the attribute name What this may happens? Because • Because in the class region we can access global variables. • Before defining any variable, Ring try to find the variable and use it if it’s found. Note: Try to avoid the global variables, use the main function and start their names with $ Tip: In large programs protect your classes and define their members using self.attribute 31.14 Using This.Attribute and This.Method() Inside class methods we have access to the object scope directly. we don’t need to use Self.attribute or Self.method to read/write attribute and call methods. But we can use braces {} while we are inside methods to access another object, In this case the current object scope will be changed while we are inside the brace. How we can get access to our class attributes and methods while we are inside braces? This can be done using This.Attribute and This.Method() Example: new point class point x=10 y=20 z=30 (continues on next page) 31.13. Using Self.Attribute and Self.Method() 208
248.
Ring Documentation, Release1.16 (continued from previous page) print() func print new UI { display(this.x,this.y,this.z) } Class UI func display x,y,z see x + nl + y + nl + z + nl 31.15 Using This in the class region as Self The class region is the region that comes after the class name and before any method. We can use This in the class region as Self. Example: func main o1 = new program { test() } ? o1 class program this.name = "My Application" this.version = "1.0" ? name ? version func test ? "Name = " + name ? "Version = " + version Output My Application 1.0 Name = My Application Version = 1.0 name: My Application version: 1.0 Note: When we use braces to change the current active object, Using This we can still point to the class. Tip: The difference between This and Self is that Self point to the current active object that we can change using braces. Remember that in most cases we don’t need to use This or Self in the class region 31.15. Using This in the class region as Self 209
249.
Ring Documentation, Release1.16 We can write class program name version Or class program name="My Application" version="1.0" Note: We use This or Self in the class region just to avoid conflict with global variables that are defined with the same name. 31.16 Default value for object attributes The default value for object attributes is NULL In Ring, the NULL value is just an empty string or a string that contains “NULL” We can check for NULL values using the isNULL() function Example: oProgram = new Program ? oProgram.name ? oProgram.version ? isNULL(oProgram.name) ? isNULL(oProgram.version) oProgram { name="My Application" version="1.0" } ? isNULL(oProgram.name) ? isNULL(oProgram.version) ? oProgram class program name version Output: NULL NULL 1 1 0 0 name: My Application version: 1.0 31.16. Default value for object attributes 210
250.
CHAPTER THIRTYTWO FUNCTIONAL PROGRAMMING In previouschapters we learned about Functions and Recursion. In this chapter we are going to learn about more Functional Programming (FP) concepts like • Pure Functions • First-class functions • Higher-order functions • Anonymous and nested functions. • Equality of functions 32.1 Pure Functions We can create pure functions (functions that doesn’t change the state) by the help of the assignment operator to copy variables (Lists & Objects) by value to create new variables instead of working on the original data that are passed to the function by reference. Example: Func Main aList = [1,2,3,4,5] aList2 = square(aList) see "aList" + nl see aList see "aList2" + nl see aList2 Func Square aPara a1 = aPara # copy the list for x in a1 x *= x next return a1 # return new list Output: aList 1 2 3 4 (continues on next page) 211
251.
Ring Documentation, Release1.16 (continued from previous page) 5 aList2 1 4 9 16 25 32.2 First-class Functions Functions inside the Ring programming language are first-class citizens, you can pass functions as parameters, return them as value or store them in variables. We can pass/return the function by typing the function name as literal like “FunctionName” or :FunctionName for example. We can pass/return functions using the variable that contains the function name. We can call function from variables contains the function name using the Call command Syntax: Call Variable([Parameters]) Example: Func Main see "before test2()" + nl f = Test2(:Test) see "after test2()" + nl call f() Func Test see "Message from test!" + nl Func Test2 f1 call f1() See "Message from test2!" + nl return f1 Output: before test2() Message from test! Message from test2! after test2() Message from test! 32.2. First-class Functions 212
252.
Ring Documentation, Release1.16 32.3 Higher-order Functions Higher-order functions are the functions that takes other functions as parameters. Example: Func Main times(5,:test) Func Test see "Message from the test function!" + nl Func Times nCount,F for x = 1 to nCount Call F() next Output: Message from the test function! Message from the test function! Message from the test function! Message from the test function! Message from the test function! 32.4 Anonymous and Nested Functions Anonymous Functions are functions without names that can be passed as parameters to other functions or stored in variables. Syntax: Func [Parameters] { [statements] } Example: test( func x,y { see "hello" + nl see "Sum : " + (x+y) + nl } ) new great { f1() } times(3, func { see "hello world" + nl } ) func test x call x(3,3) see "wow!" + nl func times n,x for t=1 to n call x() next (continues on next page) 32.3. Higher-order Functions 213
253.
Ring Documentation, Release1.16 (continued from previous page) Class great func f1 f2( func { see "Message from f1" + nl } ) func f2 x call x() Output: hello Sum : 6 wow! Message from f1 hello world hello world hello world Example: Func Main aList = [1,2,3,4] Map (aList , func x { return x*x } ) see aList aList = [4,9,14,25] Map(aList, :myfilter ) see aList aList = [11,12,13,14] Map (aList , func x { if x%2=0 return "even" else return "odd" ok }) see aList Func myfilter x if x = 9 return "True" else return "False" ok Func Map aList,cFunc for x in aList x = call cFunc(x) next Output: 1 4 9 16 False (continues on next page) 32.4. Anonymous and Nested Functions 214
254.
Ring Documentation, Release1.16 (continued from previous page) True False False odd even odd even 32.5 Equality of functions We can test if function = function or not using the ‘=’ or ‘!=’ operators Example: f1 = func { see "hello" + nl } f2 = func { see "how are you?" + nl } f3 = f1 call f1() call f2() call f3() see (f1 = f2) + nl see (f2 = f3) + nl see (f1 = f3) + nl Output: hello how are you? hello 0 0 1 32.5. Equality of functions 215
255.
CHAPTER THIRTYTHREE REFLECTION AND META-PROGRAMMING Sincethe Ring programming language is a dynamic language, we can get answers about the program code and we can modify our code during the runtime. In this chapter we will learn about this and the available functions to use. • locals() • globals() • functions() • cfunctions() • islocal() • isglobal() • isfunction() • iscfunction() • packages() • ispackage() • classes() • isclass() • packageclasses() • ispackageclass() • classname() • objectid() • isobject() • attributes() • methods() • isattribute() • isprivateattribute() • ismethod() • isprivatemethod() • addattribute() • addmethod() 216
256.
Ring Documentation, Release1.16 • getattribute() • setattribute() • mergemethods() • packagename() 33.1 locals() Function We can get a list of variables names in the current scope using the locals() function. Syntax: locals() --> a list contains the variables names in the current scope Example: test("hello") func test cMsg see cMsg + nl x = 10 y = 20 z = 30 see locals() Output: hello cmsg x y z 33.2 globals() Function We can get a list of variables names in the global scope using the globals() function. Syntax: globals() --> a list contains variables names in the global scope Example: x=10 y=20 z=30 test() func test see "message from test()" + nl + "Global Variables:" + nl see globals() 33.1. locals() Function 217
257.
Ring Documentation, Release1.16 Output: message from test() Global Variables: x y z 33.3 functions() Function We can get a list of functions names written in the Ring language using the functions() function. Syntax: functions() --> a list contains functions names Example: see functions() func f1 see "f1" + nl func f2 see "f2" + nl func f3 see "f3" + nl Output: f1 f2 f3 33.4 cfunctions() Function We can get a list of functions names written in the C language using the cfunctions() function. Syntax: cfunctions() --> a list contains functions names Example: aList = cfunctions() See "Count : " + len(aList) + nl for x in aList see x + "()" + nl next Output: 33.3. functions() Function 218
258.
Ring Documentation, Release1.16 Count : 238 len() add() del() get() clock() ... Note: The complete list is removed from the previous output. 33.5 islocal() Function We can check if a variable is defined in the local scope or not using the islocal() function. Syntax: islocal(cVariableName) --> returns 1 if the variable is defined in the local scope returns 0 if the variable is not defined in the local scope Example: test() func test x=10 y=20 see islocal("x") + nl + islocal("y") + nl + islocal("z") + nl Output: 1 1 0 33.6 isglobal() Function We can check if a variable is defined in the global scope or not using the isglobal() function. Syntax: isglobal(cVariableName) --> returns 1 if the variable is defined in the global scope returns 0 if the variable is not defined in the global ˓ →scope Example: x=10 y=20 test() (continues on next page) 33.5. islocal() Function 219
259.
Ring Documentation, Release1.16 (continued from previous page) func test see isglobal("x") + nl + isglobal("y") + nl + isglobal("z") + nl Output: 1 1 0 33.7 isfunction() Function We can check if a Ring function is defined or not using the isfunction() function. Syntax: isfunction(cFunctionName) --> returns 1 if the Ring function is defined returns 0 if the Ring function is not defined Example: see isfunction("f1") + nl + isfunction("f2") + nl + isfunction("f3") + nl func f1 see "message from f1()" + nl func f2 see "message from f2()" + nl Output: 1 1 0 33.8 iscfunction() Function We can check if a C function is defined or not using the iscfunction() function. Syntax: iscfunction(cFunctionName) --> returns 1 if the C function is defined returns 0 if the C function is not defined Example: see iscfunction("len") + nl + iscfunction("add") + nl + iscfunction("test") + nl 33.7. isfunction() Function 220
260.
Ring Documentation, Release1.16 Output: 1 1 0 33.9 packages() Function We can get a list of packages names using the packages() function. Syntax: packages() --> a list contains packages names Example: See packages() Package Package1 Class class1 Func f1 Package Package2 Class class1 Func f1 Package Package3 Class class1 Func f1 Package Package4 Class class1 Func f1 Output: package1 package2 package3 package4 33.10 ispackage() Function We can check if a package is defined or not using the ispackage() function. Syntax: ispackage(cPackageName) --> returns 1 if the Package is defined returns 0 if the Package is not defined Example: 33.9. packages() Function 221
261.
Ring Documentation, Release1.16 See ispackage("package1") + nl + ispackage("package4") + nl + ispackage("package5") + nl + ispackage("package3") + nl Package Package1 Class class1 Func f1 Package Package2 Class class1 Func f1 Package Package3 Class class1 Func f1 Package Package4 Class class1 Func f1 Output: 1 1 0 1 33.11 classes() Function We can get a list of classes names using the classes() function. Syntax: classes() --> a list contains classes names Example: See classes() Class class1 Func f1 Class class2 Func f1 Class class3 Func f1 Output: class1 class2 class3 33.11. classes() Function 222
262.
Ring Documentation, Release1.16 33.12 isclass() Function We can check if a class is defined or not using the isclass() function. Syntax: isclass(cClassName) --> returns 1 if the Class is defined returns 0 if the Class is not defined Example: see isclass("class4") + nl + isclass("class3") + nl + isclass("class2") + nl Class class1 func f1 class class2 func f1 class class3 func f1 Output: 0 1 1 33.13 packageclasses() Function We can get a list of classes names inside a package using the packageclasses() function. Syntax: packageclasses(cPackageName) --> a list contains classes names inside the package Example: see "classes in Package1" + nl see packageclasses("Package1") see "classes in Package2" + nl see packageclasses("Package2") Package Package1 Class class1 Func f1 Package Package2 Class class1 Func f1 Class class2 Func f1 Class class3 func f1 33.12. isclass() Function 223
263.
Ring Documentation, Release1.16 Output: classes in Package1 class1 classes in Package2 class1 class2 class3 33.14 ispackageclass() Function We can check if a class is defined inside package or not using the ispackageclass() function. Syntax: ispackageclass(cPackageName,cClassName) --> returns 1 if the Class is defined returns 0 if the Class is not defined Example: see ispackageclass("package1","class1") + nl + ispackageclass("package1","class2") + nl + ispackageclass("package2","class1") + nl + ispackageclass("package2","class2") + nl Package Package1 Class class1 Func f1 Package Package2 Class class1 Func f1 Class class2 Func f1 Class class3 func f1 Output: 1 0 1 1 33.15 classname() Function We can know the class name of an object using the classname() function Syntax: classname(object) --> Returns the object class name Example: 33.14. ispackageclass() Function 224
264.
Ring Documentation, Release1.16 o1 = new point o2 = new rect see classname(o1) + nl # print point see classname(o2) + nl # print rect class point class rect 33.16 objectid() Function We can know the object id using the objectid() function Syntax: objectid(object) --> Returns the object id Example: o1 = new point see objectid(o1) + nl test(o1) func test v see objectid(v) + nl Class point x y z Output: 021B5808 021B5808 33.17 isobject() Function We can check the variable to know if it’s an object or not using the isobject() function Syntax: isobject(variable) --> Returns True if it's an object, False if it's not 33.18 attributes() Function We can get the object attributes using the attributes() function Syntax: attributes(object) --> Returns a list contains the object attributes Example: 33.16. objectid() Function 225
265.
Ring Documentation, Release1.16 o1 = new point aList = attributes(o1) # we can use see attributes(o1) for t in aList see t next # print xyz Class Point x y z 33.19 methods() Function We can get the object methods using the methods() function Syntax: methods(object) --> Returns a list contains the object methods Example: o1 = new test aList = methods(o1) for x in aList cCode = "o1."+x+"()" eval(cCode) next Class Test func f1 see "hello from f1" + nl func f2 see "hello from f2" + nl func f3 see "hello from f3" + nl func f4 see "hello from f4" + nl Output: hello from f1 hello from f2 hello from f3 hello from f4 33.20 isattribute() Function We can test if the object contains an attribute or not using the isattribute() function Syntax: isattribute(object,cAttributeName) --> Returns True if the object contains the ˓ →attribute Example: 33.19. methods() Function 226
266.
Ring Documentation, Release1.16 o1 = new point see isattribute(o1,"x") + nl # print 1 see isattribute(o1,"t") + nl # print 0 see isattribute(o1,"y") + nl # print 1 see isattribute(o1,"z") + nl # print 1 class point x y z 33.21 isprivateattribute() Function We can test if the object contains a private attribute or not using the isprivateattribute() function Syntax: isprivateattribute(object,cAttributeName) --> Returns True if the object contains the private attribute Example: o1 = new person see isprivateattribute(o1,"name") + nl + isprivateattribute(o1,"address") + nl + isprivateattribute(o1,"phone") + nl + isprivateattribute(o1,"job") + nl + isprivateattribute(o1,"salary") Class Person name address phone private job salary Output: 0 0 0 1 1 33.22 ismethod() Function We can test if the object class contains a method or not using the ismethod() function Syntax: ismethod(object,cMethodName) --> Returns True if the object class contains the method Example: 33.21. isprivateattribute() Function 227
267.
Ring Documentation, Release1.16 o1 = new point see ismethod(o1,"print") + nl # print 1 mylist = [] mylist + new point see ismethod(mylist[1],"print") + nl # print 1 class point x y z func print see x + nl + y + nl + z + nl 33.23 isprivatemethod() Function We can test if the object class contains a private method or not using the isprivatemethod() function Syntax: isprivatemethod(object,cMethodName) --> Returns True if the object class contains the private method Example: o1 = new Test see isprivatemethod(o1,"f1") + nl + isprivatemethod(o1,"f2") Class Test func f1 see "message from f1()" + nl private func f2 see "message from f2()" + nl Output: 0 1 33.24 addattribute() Function We can add an attribute (or a group of attributes) to the object state (not the class) using the addattribute() function Syntax: AddAttribute(object,cAttributeName|aAttributesList) Example(1): 33.23. isprivatemethod() Function 228
268.
Ring Documentation, Release1.16 see new point {x=10 y=20 z=30} Class Point AddAttribute(self,["x","y","z"]) Example(2): o1 = new point addattribute(o1,"x") addattribute(o1,"y") addattribute(o1,"z") see o1 {x=10 y=20 z=30} class point Output: x: 10.000000 y: 20.000000 z: 30.000000 33.25 addmethod() Function We can add a method to the object class using the addmethod() function This method can be used with any object from the same class. Syntax: AddMethod(Object,cNewMethodName,cMethodName|AnonymousFunction) Example: o1 = new point { x=10 y=20 z=30 } addmethod(o1,"print", func { see x + nl + y + nl + z + nl } ) o1.print() Class point x y z Output: 10 20 30 Instead of using anonymous function to add new method to the class, we can use the function name Example: o1 = new point { x=10 y=20 z=30 } myfunc = func { see x + nl + y + nl + z + nl } addmethod(o1,"print", myfunc ) addmethod(o1,"display", myfunc ) (continues on next page) 33.25. addmethod() Function 229
269.
Ring Documentation, Release1.16 (continued from previous page) addmethod(o1,"show", myfunc ) o1.print() o1.display() o1.show() Class point x y z Output: 10 20 30 10 20 30 10 20 30 Since we add the method to the class, any object from that class can use this method Example: o1 = new point { x=10 y=20 z=30 } o2 = new point { x=100 y=200 z=300 } o3 = new point { x=50 y=150 z=250 } addmethod(o1,"print", func { see x + nl + y + nl + z + nl } ) o1.print() o2.print() o3.print() Class point x y z Output: 10 20 30 100 200 300 50 150 250 33.25. addmethod() Function 230
270.
Ring Documentation, Release1.16 33.26 getattribute() function We can get the object attribute value using the getattribute() function Syntax: GetAttribute(oObject,cAttributeName) ---> Attribute Value Example: o1 = new point see getattribute(o1,"name") + nl + getattribute(o1,"x") + nl + getattribute(o1,"y") + nl + getattribute(o1,"z") + nl Class Point x=10 y=20 z=30 name = "3D-Point" Output: 3D-Point 10 20 30 Example: We can Find a Class List Member using GetAttribute() using a function findclass() The Find uses the member name, rather than the column number myList = [new Company {position=3 name="Mahmoud" symbol="MHD"}, new Company {position=2 name="Bert" symbol="BRT"}, new Company {position=1 name="Ring" symbol="RNG"} ] see myList see nl +"=====================" + nl + nl for i = 1 to len(myList) see "Pos: "+ i +" | "+ myList[i].position +" | "+ myList[i].name + " | "+ myList[i].symbol +" | "+ nl next See findclass(myList, "MHD", "symbol") +nl ### Specify Member class name ###--------------------------------------- func findclass classList, cValue, classMember See nl + "FindClass: " +" "+ cValue + nl + nl for i = 1 to len(classList) result = getattribute( classList[i], classMember ) (continues on next page) 33.26. getattribute() function 231
271.
Ring Documentation, Release1.16 (continued from previous page) See "Result-Attr: " + i +" "+ result +nl if result = cValue j = i ok next return j ###-------------------------------------- class company position name symbol Output: Pos: 1 | 3 | Mahmoud | MHD | Pos: 2 | 2 | Bert | BRT | Pos: 3 | 1 | Ring | RNG | FindClass: MHD Result-Attr: 1 MHD Result-Attr: 2 BRT Result-Attr: 3 RNG 1 33.27 setattribute() function We can set the object attribute value using the setattribute() function Syntax: SetAttribute(oObject,cAttributeName,Value) Example: o1 = new person setattribute(o1,"cName","Mahmoud") setattribute(o1,"nSalary",1000000) setattribute(o1,"aColors",["white","blue","yellow"]) see o1 see o1.aColors Class Person cName nSalary aColors Output: cname: Mahmoud nsalary: 1000000.000000 acolors: List... (continues on next page) 33.27. setattribute() function 232
272.
Ring Documentation, Release1.16 (continued from previous page) white blue yellow 33.28 mergemethods() Function We can share methods between classes without inheritance using the MergeMethods() function This function merge class methods to another class. Syntax: MergeMethods(cClassNameDestination,cClassNameSource) Example: mergemethods("count","share") mergemethods("count2","share") o1 = new count { test() } o1 = new count2 { test() } Class Share func one see "one" + nl func two see "two" + nl func three see "three" + nl Class Display Func printline see copy("*",20) + nl Class Count from Display Func test printline() one() two() three() printline() Class Count2 from Display Func test three() two() one() printline() Output: ******************** one two three (continues on next page) 33.28. mergemethods() Function 233
273.
Ring Documentation, Release1.16 (continued from previous page) ******************** three two one ******************** 33.29 packagename() Function We can know the package name of the latest successful import command using the packagename() function Syntax: packagename() --> Returns the package name of the latest successful import Example: load "weblib.ring" import System.web see packagename() # system.web 33.29. packagename() Function 234
274.
CHAPTER THIRTYFOUR DECLARATIVE PROGRAMMING USINGNESTED STRUCTURES In this chapter we are going to learn how to build declarative programming world using nested structures on the top of object oriented. We will learn about • Creating Objects inside Lists • Composition and Returning Objects and Lists by Reference • Executing code after the end of object access • Declarative Programming on the top of Object-Oriented 34.1 Creating Objects inside Lists We can create objects inside lists during list definition. Also we can add objects to the list at any time using the Add() function or the + operator. Example: alist = [new point, new point, new point] # create list contains three objects alist + [1,2,3] # add another item to the list see "Item 4 is a list contains 3 items" + nl see alist[4] add(alist , new point) alist + new point alist[5] { x = 100 y = 200 z = 300 } alist[6] { x = 50 y = 150 z = 250 } see "Object inside item 5" + nl see alist[5] see "Object inside item 6" + nl see alist[6] class point x y z Output: 235
275.
Ring Documentation, Release1.16 Item 4 is a list contains 3 items 1 2 3 Object inside item 5 x: 100.000000 y: 200.000000 z: 300.000000 Object inside item 6 x: 50.000000 y: 150.000000 z: 250.000000 34.2 Composition and Returning Objects and Lists by Reference When we use composition and have object as one of the class attributes, when we return that object it will be returned by reference. if the caller used the assignment operator, another copy of the object will be created. The caller can avoid using the assignment operator and use the returned reference directly to access the object. The same is done also if the attribute is a list (not object). Note: Objects and Lists are treated using the same rules. When you pass them to function they are passed by reference, when you return them from functions they are returned by value except if it’s an object attribute where a return by reference will be done. Example: o1 = new Container myobj = o1.addobj() # the assignment will create another copy myobj.x = 100 myobj.y = 200 myobj.z = 300 see o1.aobjs[1] # print the object inside the container see myobj # print the copy Class Container aObjs = [] func addobj aobjs + new point return aobjs[len(aobjs)] # return object by reference Class point x = 10 y = 20 z = 30 Output: x: 10.000000 y: 20.000000 z: 30.000000 (continues on next page) 34.2. Composition and Returning Objects and Lists by Reference 236
276.
Ring Documentation, Release1.16 (continued from previous page) x: 100.000000 y: 200.000000 z: 300.000000 Example(2): func main o1 = new screen { content[point()] { x = 100 y = 200 z = 300 } content[point()] { x = 50 y = 150 z = 250 } } see o1.content[1] see o1.content[2] Class Screen content = [] func point content + new point return len(content) Class point x = 10 y = 20 z = 30 Output: x: 100.000000 y: 200.000000 z: 300.000000 x: 50.000000 y: 150.000000 z: 250.000000 Example(3): func main o1 = New Screen { point() { # access the object using reference x = 100 y = 200 z = 300 } point() { # access the object using reference x = 50 y = 150 z = 250 } } (continues on next page) 34.2. Composition and Returning Objects and Lists by Reference 237
277.
Ring Documentation, Release1.16 (continued from previous page) see o1.content[1] see o1.content[2] Class Screen content = [] func point content + new point return content[len(content)] # return the object by reference Class point x=10 y=20 z=30 Output: x: 100.000000 y: 200.000000 z: 300.000000 x: 50.000000 y: 150.000000 z: 250.000000 34.3 Executing code after the end of object access We can access an object using { } to use object attributes and methods. if the object contains a method called BraceEnd(), it will be executed before the end of the object access. Example: New Point { See "How are you?" + nl } Class Point x y z func braceend see "I'm fine, Thank you!" + nl Output: How are you? I'm fine, Thank you! 34.4 Declarative Programming on the top of Object-Oriented The next features enable us to build and use declarative programming environment using nested structures on the top of object oriented • using {} to access the object attributes and methods • BraceEnd() Method • returning objects by reference • Setter/Getter Methods (optional) Example: 34.3. Executing code after the end of object access 238
278.
Ring Documentation, Release1.16 # Declarative Programming (Nested Structures) Screen() { point() { x = 100 y = 200 z = 300 } point() { x = 50 y = 150 z = 250 } } # Functions and Classes Func screen return new screen Class Screen content = [] func point content + new point return content[len(content)] func braceend see "I have " + len(content) + " points!" Class point x=10 y=20 z=30 func braceend see self Output: x: 100.000000 y: 200.000000 z: 300.000000 x: 50.000000 y: 150.000000 z: 250.000000 I have 2 points! 34.4. Declarative Programming on the top of Object-Oriented 239
279.
Ring Documentation, Release1.16 34.5 More Beautiful Code We can get better results and a more beautiful code when we can avoid writing () after the method name when the methods doesn’t take parameters. This feature is not provided directly by the Ring language because there is a difference between object methods and object attributes. We can get a similar effect on the syntax of the code when we define a getter method for the object attribute. For example instead of defining the point() method. we will define the point attribute then the getpoint() method that will be executed once you try to get the value of the point attribute. since we write the variable name directly without () we can write point instead of point() and the method getpoint() will create the object and return the object reference for us. Example: new Container { Point { x=10 y=20 z=30 } } Class Container aObjs = [] point func getpoint aObjs + new Point return aObjs[len(aObjs)] Class Point x y z func braceend see "3D Point" + nl + x + nl + y + nl + z + nl Output 3D Point 10 20 30 34.5. More Beautiful Code 240
280.
CHAPTER THIRTYFIVE NATURAL LANGUAGE PROGRAMMING Usingthe Ring programming language, we can create Natural programming languages based on classes and objects. 35.1 History In 2010, I developed a new programming language called Supernova (developed using PWCT). This language uses a code that looks similar to Natural Language statements to create simple GUI applications. Now after five years, In the Ring programming language, we can get similar results, but now we have the ability to create/use code similar to Natural language statements in any domain that we like or need. The Ring programming language comes with the Supernova spirit, but with more generalization and with mix of other languages spirits. 35.2 Example The next example presents how to create a class that define two instructions The first instruction is : I want window The second instruction is : Window title = <expr> Also keywords that can be ignored like the ‘the’ keyword New App { I want window The window title = "hello world" } Class App # Attributes for the instruction I want window i want window nIwantwindow = 0 # Attributes for the instruction Window title # Here we don't define the window attribute again title nWindowTitle = 0 # Keywords to ignore, just give them any value the=0 func geti (continues on next page) 241
281.
Ring Documentation, Release1.16 (continued from previous page) if nIwantwindow = 0 nIwantwindow++ ok func getwant if nIwantwindow = 1 nIwantwindow++ ok func getwindow if nIwantwindow = 2 nIwantwindow= 0 see "Instruction : I want window" + nl ok if nWindowTitle = 0 nWindowTitle++ ok func settitle cValue if nWindowTitle = 1 nWindowTitle=0 see "Instruction : Window Title = " + cValue + nl ok Output: Instruction : I want window Instruction : Window Title = hello world 35.3 Change the Ring Keyword ‘And’ What if we want to connect between the two instructions using ‘and’ We have a problem because in Ring ‘and’ is a keyword We can change that using the ChangeRingKeyword command. Syntax: ChangeRingKeyword <oldkeyword> <newkeyword> Note: remember to restore the keyword again Tip: The ChangeRingKeyword command is executed in the scanner stage by the compiler (before parsing). Example: ChangeRingKeyword and _and New App { (continues on next page) 35.3. Change the Ring Keyword ‘And’ 242
282.
Ring Documentation, Release1.16 (continued from previous page) I want window and the window title = "hello world" } Class App # Attributes for the instruction I want window i want window nIwantwindow = 0 # Attributes for the instruction Window title # Here we don't define the window attribute again title nWindowTitle = 0 # Keywords to ignore, just give them any value the=0 and=0 ChangeRingKeyword _and and func geti if nIwantwindow = 0 nIwantwindow++ ok func getwant if nIwantwindow = 1 nIwantwindow++ ok func getwindow if nIwantwindow = 2 nIwantwindow= 0 see "Instruction : I want window" + nl ok if nWindowTitle = 0 nWindowTitle++ ok func settitle cValue if nWindowTitle = 1 nWindowTitle=0 see "Instruction : Window Title = " + cValue + nl ok func getand see "Using : and" + nl Output: Instruction : I want window Using : and Instruction : Window Title = hello world 35.3. Change the Ring Keyword ‘And’ 243
283.
Ring Documentation, Release1.16 35.4 Change the Ring Operator ‘+’ What if we want to define a new behavior for any operator like the “+” operator. We can do this change using the ChangeRingOperator command to hide operator (change it’s name) Then we can use the operator as identifier that we can handle it’s behaviour Syntax: ChangeRingOperator <oldoperator> <newoperator> Note: remember to restore the operator again Tip: The ChangeRingOperator command is executed in the scanner stage by the compiler (before parsing). Example: ChangeRingOperator + _+ New App { + } Class App + func get+ see "Plus operator" ChangeRingOperator _+ + Output: Plus operator 35.5 Change the ‘=’ operator to ‘is’ Example: ChangeRingKeyword and _and ChangeRingOperator = is New App { I want window and the window title is "hello world" } ChangeRingOperator is = Class App # Attributes for the instruction I want window (continues on next page) 35.4. Change the Ring Operator ‘+’ 244
284.
Ring Documentation, Release1.16 (continued from previous page) i want window nIwantwindow = 0 # Attributes for the instruction Window title # Here we don't define the window attribute again title nWindowTitle = 0 # Keywords to ignore, just give them any value the=0 and=0 ChangeRingKeyword _and and func geti if nIwantwindow = 0 nIwantwindow++ ok func getwant if nIwantwindow = 1 nIwantwindow++ ok func getwindow if nIwantwindow = 2 nIwantwindow= 0 see "Instruction : I want window" + nl ok if nWindowTitle = 0 nWindowTitle++ ok func settitle cValue if nWindowTitle = 1 nWindowTitle=0 see "Instruction : Window Title = " + cValue + nl ok 35.6 Using Eval() with our Natural Code Example: func Main cProgram = ' I want window and the window title is "hello world" ' MyLanguage(cProgram) Func MyLanguage cCode # We add to the code the instructions that change keywords and operators # Because Eval() uses a new Compiler Object (the original keywords and operatos). cCode = ' ChangeRingKeyword and _and ChangeRingOperator = is (continues on next page) 35.6. Using Eval() with our Natural Code 245
285.
Ring Documentation, Release1.16 (continued from previous page) ' + cCode New App { eval(cCode) } Class App # Attributes for the instruction I want window i want window nIwantwindow = 0 # Attributes for the instruction Window title # Here we don't define the window attribute again title nWindowTitle = 0 # Keywords to ignore, just give them any value the=0 ChangeRingKeyword and _and and=0 ChangeRingKeyword _and and func geti if nIwantwindow = 0 nIwantwindow++ ok func getwant if nIwantwindow = 1 nIwantwindow++ ok func getwindow if nIwantwindow = 2 nIwantwindow= 0 see "Instruction : I want window" + nl ok if nWindowTitle = 0 nWindowTitle++ ok func settitle cValue if nWindowTitle = 1 nWindowTitle=0 see "Instruction : Window Title = " + cValue + nl ok 35.6. Using Eval() with our Natural Code 246
286.
Ring Documentation, Release1.16 35.7 BraceStart and BraceEnd Methods We can write code that will be executed before/after using { } Example: o1 = new test { see "Hello" + nl } o1 {} class test func bracestart see "start" + nl func braceend see "end" + nl Output: start Hello end start end 35.8 BraceExprEval Method The next example demonstrates how to use the “BraceExprEval” method to get expressions in Natural code. Example: new natural { create 5 } class natural create=0 lkeyword = false func braceexpreval r if lkeyword lkeyword=false return ok see "expr eval" + nl see "type: " + type(r) see nl see "value : " see r see nl func getcreate lkeyword = true see "create" + nl Output: create expr eval type: NUMBER value : 5 35.7. BraceStart and BraceEnd Methods 247
287.
Ring Documentation, Release1.16 35.9 Real Natural Code The next example is a more advanced example # Natural Code new program { Accept 2 numbers then print the sum } # Natural Code Implementation class program # Keywords Accept=0 numbers=0 then=0 print=0 the=0 sum=0 # Execution func braceexpreval x value = x func getnumbers for x=1 to value see "Enter Number ("+x+") :" give nNumber aNumbers + nNumber next func getsum nSUm = 0 for x in aNumbers nSum+= x next see "The Sum : " + nSum private value=0 aNumbers=[] Output: Enter Number (1) :3 Enter Number (2) :4 The Sum : 7 35.10 BraceError() Method The next examples demonstrates how to use the “BraceError” method to handle errors when accessing the object using braces {}. Example: func main o1 = new point { x=10 y=20 z=30 TEST SEE test } class point x y z func braceerror see "Handle Error!" + nl SEE "Message :" + cCatchError + nl if ( left(cCatchError,11) = "Error (R24)" ) and not isattribute(self, ˓ →"test") (continues on next page) 35.9. Real Natural Code 248
288.
Ring Documentation, Release1.16 (continued from previous page) see "add attribute" + nl addattribute(self,"test") test = 10 ok see "done" + nl return Output: Handle Error! Message :Error (R24) : Using uninitialized variable : test add attribute done 10 Example: new point { x=10 y=20 z=30 test() see "mmm..." + NL } class point x y z func braceerror see "Handle Error!" + nl see "Message :" + cCatchError + nl see self see "Done" + NL Output: Handle Error! Message :Error (R3) : Calling Function without definition !: test x: 10.000000 y: 20.000000 z: 30.000000 Done mmm... 35.11 Clean Natural Code Instead of typing the literal as “literal” we can accept the words directly. Example: The next example accept hello world instead of “hello world” But this example uses braceend() to check the end of the instruction This means that this class process only one natural statement that end with literal. ChangeRingKeyword and _and New App (continues on next page) 35.11. Clean Natural Code 249
289.
Ring Documentation, Release1.16 (continued from previous page) { I want window and the window title is hello world } Class App # Attributes for the instruction I want window i want window nIwantwindow = 0 # Attributes for the instruction Window title # Here we don't define the window attribute again title is nWindowTitle = 0 # Keywords to ignore, just give them any value the=0 and=0 # Data literal = "" ChangeRingKeyword _and and func geti if nIwantwindow = 0 nIwantwindow++ ok func getwant if nIwantwindow = 1 nIwantwindow++ ok func getwindow if nIwantwindow = 2 nIwantwindow= 0 see "Instruction : I want window" + nl ok if nWindowTitle = 0 nWindowTitle++ ok func gettitle if nWindowTitle = 1 nWindowTitle=2 ok func getis if nWindowTitle = 2 nWindowTitle=3 ok func braceend if nWindowTitle = 3 see "Instruction : Window Title = " + literal + nl nWindowTitle = 0 ok func braceerror c= substr(cCatchError,":") (continues on next page) 35.11. Clean Natural Code 250
290.
Ring Documentation, Release1.16 (continued from previous page) while c > 0 c= substr(cCatchError,":") cCatchError=substr(cCatchError,c+1) end literal += substr(cCatchError,1) 35.11. Clean Natural Code 251
291.
CHAPTER THIRTYSIX USING THE NATURALLIBRARY In this chapter we will learn how to use the Natural Library to quickly define a language that contains a group of commands. To start using the library, We need to call naturallib.ring load "naturallib.ring" After loading the library, We can use the NaturalLanguage class that contains the next methods :- • SetLanguageName(cLanguageName) • setCommandsPath(cFolder) • SetPackageName(cPackageName) • UseCommand(cCommandName) • SetOperators(cOperators) • RunFile(cFileName) • RunString(cString) 36.1 Natural Library - Demo Program We will write the natural code in a Text file, for example program.txt File: program.txt Welcome to the Ring programming language! What you are reading now is not comments, I swear! After many years of programming I decided to think different about programming and solve the problems in a better way. We are writing commands or code and the Ring language is reading it to understand us! Sure, What you are seeing now is just ***part of the code - Not the Complete Program*** You have to write little things before and after this part to be able to run it! It is the natural part of our code where we can write in English, Arabic or any Natural Language Then we will tell the computer through the Ring language what must happens! in a way that we can scale for large frameworks and programs. (continues on next page) 252
292.
Ring Documentation, Release1.16 (continued from previous page) Just imagine what will happens to the world of programming once we create many powerful frameworks using the Ring language that uses this way (Natural Programming). For example When we say Hello to the Machine, It can reply! and when we say count from 1 to 5 it will understand us, Also if we said count from 5 to 1 it will understand us too! You can see the Output window! This Goal is not new, but the Ring language comes with an innovative solution to this problem. Output: Hello, Sir! The Numbers! 1 2 3 4 5 I will count Again! 5 4 3 2 1 To execute the natural code, We have start.ring In start.ring we define the language and the commands. File: start.ring load "stdlib.ring" load "naturallib.ring" New NaturalLanguage { SetLanguageName(:MyLanguage) SetCommandsPath(CurrentDir()+"/../command") SetPackageName("MyLanguage.Natural") UseCommand(:Hello) UseCommand(:Count) (continues on next page) 36.1. Natural Library - Demo Program 253
293.
Ring Documentation, Release1.16 (continued from previous page) RunFile("program.txt") } We defined a language called MyLanguage, We have folder for the language commands. Each command will define a class that belong to the MyLanguage.Natural package. We will define two commands, Hello and Count. So we must have two files for defining the commands in the CurrentDir()+”/../command” folder File: hello.ring DefineNaturalCommand.SyntaxIsKeyword([ :Package = "MyLanguage.Natural", :Keyword = :hello, :Function = func { See "Hello, Sir!" + nl + nl } ]) File: count.ring DefineNaturalCommand.SyntaxIsKeywordNumberNumber([ :Package = "MyLanguage.Natural", :Keyword = :count, :Function = func { if not isattribute(self,:count_times) { AddAttribute(self,:count_times) Count_Times = 0 } if Expr(1) > Expr(2) { nStep = -1 else nStep = 1 } if Count_Times = 0 { see nl+"The Numbers!" + nl Count_Times++ else see nl + "I will count Again!" +nl } for x = Expr(1) to Expr(2) step nStep { see nl+x+nl } CommandReturn(fabs(Expr(1)-Expr(2))+1) } ]) 36.1. Natural Library - Demo Program 254
294.
Ring Documentation, Release1.16 36.2 Defining Commands To define new command we can use the DefineNaturalCommand object This object provides the next methods :- • SyntaxIsKeyword(aPara) • SyntaxIsKeywordNumber(aPara) • SyntaxIsKeywordNumberNumber(aPara) • SyntaxIsKeywordNumbers(aPara,nCount) • SyntaxIsKeywordString(aPara) • SyntaxIsKeywordStringString(aPara) • SyntaxIsKeywordStrings(aPara,nCount) • SyntaxIsKeywordExpression(aPara) • SyntaxIsKeywordExpressionExpression(aPara) • SyntaxIsKeywordExpressions(aPara,nCount) • SyntaxIsCommand(aPara) • SyntaxIsCommandNumber(aPara) • SyntaxIsCommandNumberNumber(aPara) • SyntaxIsCommandNumbers(aPara,nCount) • SyntaxIsCommandString(aPara) • SyntaxIsCommandStringString(aPara) • SyntaxIsCommandStrings(aPara,nCount) • SyntaxIsCommandExpression(aPara) • SyntaxIsCommandExpressionExpression(aPara) • SyntaxIsCommandExpressions(aPara,nCount) File: mylanguage.ring load "stdlib.ring" load "naturallib.ring" MyLanguage = New NaturalLanguage { SetLanguageName(:MyLanguage) setCommandsPath(CurrentDir()+"/../command") SetPackageName("MyLanguage.Natural") UseCommand(:Hello) UseCommand(:Count) UseCommand(:Print) UseCommand(:IWantWindow) UseCommand(:WindowTitleIs) UseCommand(:IWantButton) } Example (1) In the next example we will define the Print command. 36.2. Defining Commands 255
295.
Ring Documentation, Release1.16 We will use the SyntaxIsKeywordExpression() Method. We pass list (as Hash) to the method. We determine the package name, the keyword and the function that will be executed. Inside this function we uses the Expr(nExprNumber) function to get the expression value that the user will write after the keyword. File: print.ring DefineNaturalCommand.SyntaxIsKeywordExpression([ :Package = "MyLanguage.Natural", :Keyword = :print, :Function = func { See Expr(1) } ]) Usage: load "mylanguage.ring" MyLanguage.RunString(' print "Hello, World!" ') Output: Hello, World! Example (2) File: iwantwindow.ring DefineNaturalCommand.SyntaxIsCommand([ :Package = "MyLanguage.Natural", :Command = "i want window", :Function = func { See "Command: I want window" + nl } ]) Usage: load "mylanguage.ring" MyLanguage.RunString(' i want window ') Output: Command: I want window Example (3) File: windowtitleis.ring 36.2. Defining Commands 256
296.
Ring Documentation, Release1.16 DefineNaturalCommand.SyntaxIsCommandString([ :Package = "MyLanguage.Natural", :Command = "window title is", :Function = func { See "Command: Window title is " + Expr(1) + nl } ]) Usage: load "mylanguage.ring" MyLanguage.RunString(' I want window and the window title is "Hello World" ') Output: Command: I want window Command: Window title is Hello World 36.3 Natural Library - Operators In the next example we uses the Count command without using operators load "mylanguage.ring" MyLanguage.RunString(" Hello Count 1 5 Count 5 1 ") We can add more description load "mylanguage.ring" MyLanguage.RunString(" Hello, Please Count from 1 to 5 then count from 5 to 1 ") Also we can use operators like “(” and “)” around the instruction load "mylanguage.ring" MyLanguage { SetOperators("()") RunString(" Here we will play and will try something that looks like Lisp Syntax (count (count 1 5) (count 20 15)) Just for fun! ") } 36.3. Natural Library - Operators 257
297.
Ring Documentation, Release1.16 36.4 Defining commands using classes This section is related to the implementation details. When we define new command, Each command is defined by the Natural Library as a class. We have the choice to define commands using the simple interface provided by the DefineNaturalCommand object or by defining new class as in the next examples. If we used DefineNaturalCommand (More Simple), The class will be defined during the runtime. File: hello.ring Package MyLanguage.Natural class Hello func AddAttributes_Hello AddAttribute(self,:hello) func GetHello See "Hello, Sir!" + nl + nl File: count.ring Package MyLanguage.Natural class Count func Getcount StartCommand() CommandData()[:name] = :Count CommandData()[:nExpr] = 0 CommandData()[:aExpr] = [] func BraceExprEval_Count nValue if isCommand() and CommandData()[:name] = :Count { if isNumber(nValue) { CommandData()[:nExpr]++ CommandData()[:aExpr] + nValue if CommandData()[:nExpr] = 2 { Count_Execute() } } } func AddAttributes_Count AddAttribute(self,:count) func Count_Execute if not isattribute(self,:count_times) { AddAttribute(self,:count_times) Count_Times = 0 } if Expr(1) > Expr(2) { nStep = -1 else nStep = 1 (continues on next page) 36.4. Defining commands using classes 258
298.
Ring Documentation, Release1.16 (continued from previous page) } if Count_Times = 0 { see nl+"The Numbers!" + nl Count_Times++ else see nl + "I will count Again!" +nl } for x = Expr(1) to Expr(2) step nStep { see nl+x+nl } CommandReturn(fabs(Expr(1)-Expr(2))+1) 36.4. Defining commands using classes 259
299.
CHAPTER THIRTYSEVEN SCOPE RULES FORVARIABLES AND ATTRIBUTES In this chapter we will learn about scope rules and how Ring find variables. Also we will learn about conflicts and how to solve/avoid them. The next information are important once you start developing large applications using Ring These application may uses • Global variables (Try to avoid them) • Classes (Object-Oriented) • braces { } to access objects • Declarative Programming • Natural Programming 37.1 Three Scopes In Ring we have three scopes :- (1) Public/Global Scope - Each variable you define in the statements part (before functions and classes) (2) Object Scope - When you are inside an object (Inside class method or using { } to access the object ) (3) Local Scope - Related to functions and methods 37.2 Defining Variables and Variables Access (1) Ring uses lexical scoping, i.e. the scope of the variable is based on where we defined the variable. (2) Inside braces { } when you access an object, You will change the current active object scope to this object scope but you still can access the global scope and the local scope. (3) After the ‘Class’ keyword and the class name, when you write variable names to be defined as attributes, You still can access the global scope. In this region (class region - after the class name and before methods) we have • Global Scope —-> The Global Scope • Object Scope —-> The Object Scope • Local Scope —-> The Object Scope 260
300.
Ring Documentation, Release1.16 Note: Since the local scope in the class region point also to the object scope in this region, we can use nested braces and still have access to the object scope of the class through the local scope. Tip: You can create windows and controls as attributes by defining them in this region. Tip: In the class region if you created objects and used braces {} to access them then using self.attribute inside braces will use the class (not the object that you access) because you have access to the class through the local scope. (4) Function Parameters are automatically defined in the local scope. 37.3 How Ring find the variable? 1 - Search First in the Local Scope if not found ! 2 - Search in the Object Scope if not found ! 3 - Search in the public scope if not found —-> Runtime Error if found —-> Check if we can do optimization to avoid searching next time (Cache / Pointers for performance). 37.4 Using Object.Attribute When we use object.attribute the search will be in the object attributes only. I.e. no search will be done in the local scope or in the global scope for the object attribute. Note: Using self.attribute will search for the first self before searching for attributes. 37.5 The Self Object The self object is a reference to the current object that we can use from the class methods. When we are inside class method and use Self we mean the object that will be created from this class. Inside the class methods if we used Braces { } this will change the current object scope and self will be changed also inside braces to reference the object that we access using Braces. Inside the Class Region (after the class name and before any method) we have access to the object through the object scope and the local scope also. In this region using Self will always be a reference to the class object. if we used Braces to change the object scope then used Self inside Braces, Also self will be a reference to the class object (not the object that we already access using braces) because in the class region we have :- 37.3. How Ring find the variable? 261
301.
Ring Documentation, Release1.16 • Global Scope —> Global Scope • Object Scope —> Object Scope • Local Scope —> Object Scope And using Braces changes the object scope only (not the local scope) and when Ring search for variables it will search in the Local Scope first so it will find self in the class that we are inside. 37.6 How Ring Define Variables and Attributes Ring will use the variable name in the Assignment operation 1 - Search using the variable name 2 - If not found —> Avoid the runtime error and define the variable in the current scope 3 - If found —> Use the variable and don’t define anything in the current scope • In the global region (before any function or class) the current scope is the global scope. • In the class region (after the class name and before any method) the current scope is the object attributes. • In Functions and methods the current scope is the local scope. 37.7 Conflict between Global Variables and Class Attributes Look at this example: name = "test" o1 = new person see o1 class person name address phone In the previous example we have a global variable called ‘name’ inside the class person. when we use the variable ‘name’, Ring will start the search operation and will try to find it. if found —> Use it if not found —> Define new attribute But the variable name is a global variable, so it will be found and used! We will not have the attribute name! added to the object. Solution (1) - Use the Main Function func main name = "test" o1 = new person see o1 class person name (continues on next page) 37.6. How Ring Define Variables and Attributes 262
302.
Ring Documentation, Release1.16 (continued from previous page) address phone Solution (2) - Use special mark for global variable names like $ $name = "test" o1 = new person see o1 class person name address phone Solution (3) - Use the AddAttribute() Method name = "test" o1 = new person see o1 class person AddAttribute(self,"name") address phone Solution (4) - Use self before the attribute name name = "test" o1 = new person see o1 class person self.name address phone So what is the best solution to this conflict? 1 - Use the $ Mark for global variables 2 - Optional : Try to avoid global variables and use the Main function In practice i do both of them. The other solution • Use self before the attribute name or use AddAttribute() 37.7. Conflict between Global Variables and Class Attributes 263
303.
Ring Documentation, Release1.16 37.8 Conflict between Class Attributes and Local Variables This conflict may happen when we access the object using braces Example: func main name = "nice" o1 = new person {name="mahmoud" address="Egypt" phone = 000 } see o1 class person name address phone In the previous example we have the local variable name. The value of this variable will be set to “mahmoud” instead of the object attribute. Solution (1) : Just use Self func main name = "nice" o1 = new person {self.name="mahmoud" address="Egypt" phone = 000 } see o1 class person name address phone Solution (2) : Change the Local variable name func main cName = "nice" o1 = new person {name="mahmoud" address="Egypt" phone = 000 } see o1 class person name address phone Solution (3) : Change Braces and use the Dot operator func main name = "nice" o1 = new person o1.name ="mahmoud" o1.address ="Egypt" o1.phone = 000 see o1 class person name address phone 37.8. Conflict between Class Attributes and Local Variables 264
304.
Ring Documentation, Release1.16 37.9 Using Braces to access objects inside Class Methods Remember that we have Three scopes (Local Scope, Object Scope and Global Scope) and when we are inside a class method, we expect that we have access to the object attributes and methods and this is true until we use braces to access another object attributes and methods because in this case our object scope will be switched to another object. new point { test() } class point x=10 y=20 func test see x + nl + y + nl # works fine myobj = new otherclass { see name + nl see x + nl + y + nl # error ! } class otherclass name = "test" Output: 10 20 test Line 8 Error (R24) : Using uninitialized variable : x In method test() in file methodbraceerror.ring called from line 5 in file methodbraceerror.ring Now what we will do to solve the previous problem? Solution (1) : Write the code that access the class attributes outside braces. new point { test() } class point x=10 y=20 func test see x + nl + y + nl # works fine myobj = new otherclass { see name + nl } see x + nl + y + nl # Outside braces - works fine class otherclass name = "test" Output: 10 20 test 10 20 Solution (2) : Don’t Use Braces 37.9. Using Braces to access objects inside Class Methods 265
305.
Ring Documentation, Release1.16 new point { test() } class point x=10 y=20 func test see x + nl + y + nl myobj = new otherclass see myobj.name see x + nl + y + nl class otherclass name = "test" Solution (3) : Copy the self object We may use this solution if we want to use braces and get access to the class attributes (Just Reading). new point { test() } class point x=10 y=20 func test oSelf = self see x + nl + y + nl myobj = new otherclass { see name + nl see oself.x + nl + oself.y + nl } class otherclass name = "test" Output: 10 20 test 10 20 Now look at this line oself = self The problem with the previous line is that we will have a new copy from the object Because in Ring the assignment operator copy lists and objects by value (not by reference). When we access the new object attributes (reading) we don’t have problems But if we modified the object attributes (Then we will modify the copy!). Note: We can use braces again with the copy new point { test() } class point (continues on next page) 37.9. Using Braces to access objects inside Class Methods 266
306.
Ring Documentation, Release1.16 (continued from previous page) x=10 y=20 func test oSelf = self see x + nl + y + nl myobj = new otherclass { see name + nl oSelf { see x + nl + y + nl } } class otherclass name = "test" In a GUI application, we may create a class contains the window objects as attributes to be able to access the controls from different methods. Remember the previous information when you try to access objects using braces inside methods because in this case you can’t access the object attributes directly and if you copied the self object you will work on a copy and the new controls that you create will be related to the copy and you can’t access them. 37.10 Accessing the class attributes from braces inside class meth- ods We access the class attributes directly from the class methods, also we have the choice to use the Self reference before the attribute/method name. Using Braces {} inside class method change the active object scope and prevent us from getting direct access to the class attributes. Also using Self will not help because the Self reference will be changed to the object that we access using Braces. In this case if you want to read an attribute you have to copy the Self object before using Braces and if you want to modify an attribute you have to the copy from local variable to the object attribute after using Braces. This case happens when you want to read/modify attribute instead braces. Class MyApp oCon # Attribute # some code here Func OpenDatabase # some code here new QSqlDatabase() { oCon = addDatabase("QSQLITE") { setDatabaseName("weighthistory.db") open() } } self.oCon = oCon # some code here In the previous example we want to create the connection object and save it inside the oCon attribute. The object is an output from the addDatabase() method that we use after accessing the QSQLDatabase() object. Inside braces we can’t use the Self reference to use the object created from the MyApp class, Because the Self reference here will be to the object that we access using Braces. 37.10. Accessing the class attributes from braces inside class methods 267
307.
Ring Documentation, Release1.16 We solved the problem in the previous example by creating a local variable called oCon then after Braces we copied that variable to the oCon attribute. The next code is another solution. Class MyApp oCon # Attribute # some code here Func OpenDatabase # some code here oCon = new QSqlDatabase() oCon = oCon.addDatabase("QSQLITE") { setDatabaseName("weighthistory.db") Open() } # some code here The next code is a better solution. Class MyApp oCon # Attribute # some code here Func OpenDatabase # some code here new QSqlDatabase() { this.oCon = addDatabase("QSQLITE") { setDatabaseName("weighthistory.db") Open() } } # some code here Note: We used this.attribute to access the class attribute (oCon) while we are inside Braces. 37.11 Creating a Class for each Window in GUI applications A good way for creating classes for windows is to define the window directly after the class name In this area you can use nested braces without problems to define the window and the controls, and they will be attributes that you can access from methods. Example: Load "guilib.ring" new qApp { $ObjectName = "oFirstWindow" (continues on next page) 37.11. Creating a Class for each Window in GUI applications 268
308.
Ring Documentation, Release1.16 (continued from previous page) oFirstWindow = new FirstWindow $ObjectName = "oSecondWindow" oSecondWindow = new SecondWindow exec() } Class FirstWindow win = new qWidget() { setgeometry(0,50,300,200) setWindowTitle("First Window") label1 = new qLabel(win) { setgeometry(10,10,300,30) setText("0") } btn1 = new qPushButton(win) { move(100,100) setText("Increment") setClickEvent($ObjectName+".increment()") } show() } Func Increment label1 { setText( "" + ( 0 + text() + 1 ) ) } Class SecondWindow win = new qWidget() { setgeometry(400,50,300,200) setWindowTitle("Second Window") label1 = new qLabel(win) { setgeometry(10,10,300,30) setText("0") } btn1 = new qPushButton(win) { move(100,100) setText("Decrement") setClickEvent($ObjectName+".decrement()") } show() } Func Decrement label1 { setText( "" + ( 0 + text() - 1 ) ) } 37.11. Creating a Class for each Window in GUI applications 269
309.
Ring Documentation, Release1.16 37.12 Conflict between self inside braces and self in the class region In the class region (after the class name and before any methods) we define the attributes. In this region we have access to the global scope and the local scope will point to the object scope. Three Scopes • Global Scope —> Global Scope • Object Scope —> Object Scope • Local Scope —> Object Scope Look at this example New Account { see aFriends } Class Account name = "Mahmoud" aFriends = [] aFriends + new Friend { name = "Gal" } aFriends + new Friend { name = "Bert" } Class Friend name Output: name: NULL name: NULL The problem in the previous example is that the Class account contains an attribute called “name” and the Friend class contains an attribute called “name” also. If you tried using self.name inside braces you will get the same result! New Account { see aFriends } Class Account name = "Mahmoud" aFriends = [] aFriends + new Friend { self.name = "Gal" } aFriends + new Friend { self.name = "Bert" } Class Friend name 37.12. Conflict between self inside braces and self in the class region 270
310.
Ring Documentation, Release1.16 So why using self.name inside braces doesn’t solve this conflict? Because after the class region we have • global scope —> global scope • object scope —> object scope (Account Class) • local scope —> local scope (Account Class) When we use braces we change the object scope, so we have • global scope —> global scope • object scope —> object scope (Friend Class) • local scope —> local scope (Account Class) Ring search in the local scope first, so using self.name will use the Account class. There are many solution Solution (1) : Access the object through the list New Account { see aFriends } Class Account name = "Mahmoud" aFriends = [] aFriends + new Friend aFriends[len(aFriends)] { aFriends[len(aFriends)].name = "Gal" } aFriends + new Friend aFriends[len(aFriends)] { aFriends[len(aFriends)].name = "Bert" } Class Friend name Solution (2) : Create Method in the friend class to set the name attribute. New Account { see aFriends } Class Account name = "Mahmoud" aFriends = [] aFriends + new Friend { setname("Gal") } aFriends + new Friend { setname("Bert") } Class Friend name (continues on next page) 37.12. Conflict between self inside braces and self in the class region 271
311.
Ring Documentation, Release1.16 (continued from previous page) func setname cName name = cName Solution (3) : Create a method in the account class to set the attribute New Account { see aFriends } Class Account name = "Mahmoud" aFriends = [] friend("Gal") friend("Bert") func friend cName aFriends + new Friend { name = cName } Class Friend name Solution (4) : Declarative Programming New Account { name = "mahmoud" friend { name = "Gal" } friend { name = "Bert" } see aFriends } Class Account name aFriends = [] friend func getfriend aFriends + new Friend return aFriends[len(aFriends)] Class Friend name Output: name: Gal name: Bert 37.12. Conflict between self inside braces and self in the class region 272
312.
Ring Documentation, Release1.16 37.13 Using braces to escape from the current object scope Since braces change the current object scope to another object. we can use it to do some work without modifying the class attributes and using the same variable names. new point {x=10 y=20 z=30 start() } class point x y z func start see self # print the x y z values (10,20,30) new Local { x = 100 y = 200 z = 300 } see self # print the x y z values (10,20,30) see x + nl # will print 100 see y + nl # will print 200 see z + nl # will print 300 Self { # NO Advantage - Search is done in local scope first see x + nl # will print 100 see y + nl # will print 200 see z + nl # will print 300 } see self.x + nl # will print 10 see self.y + nl # will print 20 see self.z + nl # will print 30 class Local Output: x: 10.000000 y: 20.000000 z: 30.000000 x: 10.000000 y: 20.000000 z: 30.000000 100 200 300 100 200 300 10 20 30 37.13. Using braces to escape from the current object scope 273
313.
Ring Documentation, Release1.16 37.14 The For Loops uses the local scope Starting from Ring 1.8, when the For Loop defines new identifier (variable) it will define it in the local scope. Example: x = 10 ? x # Print 10 test1() ? x # Print 10 test2() ? x # Print 10 func test1 for x = 1 to 5 next ? x # Print 6 func test2 list = 1:5 for x in list next ? x # Print NULL (The "For In" loop will kill the reference after the ˓ →loop) Output: 10 6 10 NULL 10 37.15 Summary of Scope Rules At first remember that 1 - Each programming language comes with it’s scope rules based on the language goals 2 - Programming in the small is different than Programming in the Large 3 - Some programming language are designed for developing small programs while others are designed for large programs 4 - In programming, If we have access to more than one scope - Then problems may come if we don’t manage things correctly 5 - It’s always more secure to reduce the number of visible scopes 6 - Some programming languages force you to manage the scope in some way, while others not! In Ring 1 - Special and very simple scope rules that are designed for Flexibility first then Security 2 - Ring is designed to support programming in the small and programming in the large. 37.14. The For Loops uses the local scope 274
314.
Ring Documentation, Release1.16 3 - The language provide the different programming paradigms that you may select from based on the project size. Errors comes only if you selected a bad paradigm for the target project or you are using the paradigm in a way that is not correct or at least not common. 4 - In Ring you have the choice, you can use global variables or avoid them. you can give them a special $ mark or leave them. you can use object-oriented or stay with procedures. you can use the class region (after the class name and before any method) just for attributes or use it for code too. 5 - Just read the next scope rules and think about them then use them in your favorite way. Scope Rules: 1 - At any place in our program code we have only at maximum Three Scopes (Local Scope, Object Scope and Global Scope). 2 - When Ring find a variable it will search in the local scope first then in the object scope then in the global scope. 3 - At any time inside procedures or methods you can use braces { } to access an object and change the current object scope. 4 - In the class region (After the class name and before any method) this is a special region where both of the object scope and the local scope point to the object scope. I.e. No local variables where each variable you define in this region will become an attribute. 5 - Before defining any variable (in any scope and in the class region too) a search process will be done to use the variable if it’s found. 6 - Functions and Methods parameters are defined automatically as local variables to these functions or methods. 7 - Using Object.Attribute will search in the object attributes only. 8 - Using Self.Attribute will lead to a search for Self first then search in Self Attributes. 9 - The Self reference inside class region (after the class name and before any method) always point to the object scope created from the class. 10- The Self reference inside methods will be changed when we uses Braces to be a reference to the object that we access. 11- Writing variable names directly in the class region (after the class name and before any method) means using them or define then (in order). 12- Using self.attribute in the class region reduce search to the object scope (avoid conflict with global scope). From these rules you can understand all types of conflicts and why you may have them and how to avoid them Simple advices to avoid any conflict and use the scope rules in a better way 1 - Try to avoid global variables 2 - Use the Main Function - This will help you to avoid global variables 3 - If you are going to use many global variables use the $ mark before the variable name 4 - In the class region if you don’t respect the advice number three ($) then use self.attribute when you define your attributes 5 - You can use object.attribute and object.method() instead of object { attribute } and object { method() } if you don’t like changing the object scope. 6 - If you will use nested braces in a class - think about using the class region if possible because in this region you will have access to the object that you access using { } + access to the class attributes 7 - If you are inside a class method and used nested braces you will change the object scope with each brace and you will loss the access to the class attributes directly but you have access to the local scope before and after using brace 37.15. Summary of Scope Rules 275
315.
Ring Documentation, Release1.16 { } , if you will read/modify the class attribute from braces then use This.Attribute because using ‘This’ means (The object created from this class) while using ‘Self’ means (The object in the current object scope). After understanding all of the previous points, You will master this topic. 37.15. Summary of Scope Rules 276
316.
CHAPTER THIRTYEIGHT SCOPE RULES FORFUNCTIONS AND METHODS In this chapter we will learn about the scope rules for functions and methods. You need to know the next information once you started using Ring for large applications. These applications may contains and use • Many Packages and Classes written in Ring • Many Functions written in Ring • Standard Ring Functions (Written in C language) • Functions and Classes written in C/C++ languages 38.1 How Ring find the Functions and Methods? When you call a method or function, Ring will start a search process to find this function If found –> Call the function and store the function pointer in the cache so Ring can use it again with doing another search. If not found —> Runtime error message (That you can avoid using Try/Catch) How the search process is done? Search for functions/methods follow the next order 1 - Search in methods (if we are inside class method or object using braces {}) 2 - Search in functions written by the programmer using Ring Code 3 - Search in functions written in C/C++ like standard Ring functions This enable us to write clean code inside classes methods and avoid any conflict with functions. If we want to call a function with the same name as a method in the class we will need a wrapper function or we will access a temp. object using { } then call that function there. We can replace C/C++ Functions with Ring Functions. We can replace Ring Functions with Ring Methods. Note: Using self.method() is not necessary in any use case. 277
317.
Ring Documentation, Release1.16 Tip: We can use this.method() to escape from the current active scope that we access using braces {} and call a method in the class that we are inside. 38.2 Example about Sharing Names between Functions and Methods Look at the next example func main o1 = new myclass { test() test2() } test2() func f1 see "f1 function" + nl func f2 see "f2 function" + nl func f3 see "f3 function" + nl func test2 myline() see "test2 function" + nl new myclass { f1() f2() f3() self.f3() } myobj = new myclass myobj.f3() myline() func myline see copy("=",40) + nl Class myclass func test myline() see "test method" + nl f1() f2() f3() myline() func f3 see "f3 method" + nl func test2 myline() see "test2 method" + nl self { f1() (continues on next page) 38.2. Example about Sharing Names between Functions and Methods 278
318.
Ring Documentation, Release1.16 (continued from previous page) f2() f3() } myline() Output: ======================================== test method f1 function f2 function f3 method ======================================== ======================================== test2 method f1 function f2 function f3 method ======================================== ======================================== test2 function f1 function f2 function f3 method f3 method f3 method ======================================== 38.3 Calling a function sharing the name with a method in the current class In the previous example we have a function called f3() and we have a method called f3() How we can call the f3() function from the test() method ? Solution (1) : Change the current object scope to another object scope In this solution we will have an empty class called local that we will use to change the current object scope. func main o1 = new myclass { test()} func f1 see "f1 function" + nl func f2 see "f2 function" + nl func f3 see "f3 function" + nl func myline see copy("=",40) + nl (continues on next page) 38.3. Calling a function sharing the name with a method in the current class 279
319.
Ring Documentation, Release1.16 (continued from previous page) Class myclass func test myline() see "test method" + nl f1() f2() f3() # call f3() method new local { f3() } # call f3() function myline() func f3 see "f3 method" + nl class local Output: ======================================== test method f1 function f2 function f3 method f3 function ======================================== 38.3. Calling a function sharing the name with a method in the current class 280
320.
CHAPTER THIRTYNINE SYNTAX FLEXIBILITY In thischapter we will learn about some options that are provided automatically by the Ring compiler for syntax flexibility. 39.1 Change Language Keywords We can change any keyword using the ChangeRingKeyword command. Note: Remember to restore the keyword again if the team will mix between styles in the same project. Tip: The ChangeRingKeyword command is executed in the scanner stage by the compiler (before parsing). Syntax: ChangeRingKeyword <oldkeyword> <newkeyword> Example: ChangeRingKeyword see print print "welcome" + nl ChangeRingKeyword print see see "Welcome" + nl Example: ChangeRingKeyword func function ChangeRingKeyword see print ChangeRingKeyword ok endif ChangeRingKeyword next endfor ChangeRingKeyword end endwhile x = 10 while x > 0 print "x = " + x + nl for t = 1 to 10 if t = 3 (continues on next page) 281
321.
Ring Documentation, Release1.16 (continued from previous page) print "number three" + nl endif endfor x-- endwhile test() function test print "message from test" + nl ChangeRingKeyword function func ChangeRingKeyword print see ChangeRingKeyword endif ok ChangeRingKeyword endfor next ChangeRingKeyword endwhile end 39.2 Change Language Operators We can change any operator using the ChangeRingOperator command. Note: Remember to restore the operator again if the team will mix between styles in the same project. Tip: The ChangeRingOperartor command is executed in the scanner stage by the compiler (before parsing). Syntax: ChangeRingOperator <oldkeyword> <newkeyword> Example: The next program hide the + operator by changing it to _+ changeringoperator + _+ changeringkeyword SEE PRINT try print 5 + 10 catch print nl print "error" print nl done changeringoperator _+ + The next program change the + operator to “plus”. changeringoperator + plus changeringkeyword SEE PRINT Print 5 plus 5 (continues on next page) 39.2. Change Language Operators 282
322.
Ring Documentation, Release1.16 (continued from previous page) changeringoperator plus + changeringkeyword PRINT SEE 39.3 Load Syntax Files You may store a group of ChangeRingKeyword and ChangeRingOperator commands in a file to use later in many source files. You can’t use the Load command to call these files because • ChangeRingKeyword and ChangeRingOperator commands are executed in the scanner phase by the compiler (before parsing). • The load command is executed in the parsing phase (after the scanner phase). Solution: Use the LoadSyntax Command which is executed in the scanner phase. Syntax: LoadSyntax "syntaxfile.ring" Example: File : StyleBasicOn.ring ChangeRingKeyword see print ChangeRingKeyword ok endif ChangeRingKeyword next endfor ChangeRingKeyword end endwhile File : StyleBasicOff.ring ChangeRingKeyword print see ChangeRingKeyword endif ok ChangeRingKeyword endfor next ChangeRingKeyword endwhile end File : UseStyleBasic.ring LoadSyntax "stylebasicon.ring" x = 10 while x > 0 print "x = " + x + nl for t = 1 to 10 if t = 3 print "number three" + nl endif endfor x-- endwhile LoadSyntax "stylebasicoff.ring" see "done" + nl 39.3. Load Syntax Files 283
323.
Ring Documentation, Release1.16 Note: files called by the LoadSyntax command must contains ChangeRingKeyword and ChangeRingOperator com- mands only. Tip: files called by the LoadSyntax command doesn’t support functions, packages and classes. just imperative commands only. Note: Using this feature you can create many styles that you can use in the same project and you can support Ring translation to other languages like Arabic, French and so on. Tip: The effect of LoadSyntax command is related to the current source code file only. 39.4 Using “()” around the function parameters We can use () around the function parameters (optional). Example: hello() sum(3,4) func hello() see "Hello" + nl func sum(x,y) see x+y+nl Output: Hello 7 Example: myfunc = func x,y { see x + y + nl } call myfunc (3,4) myfunc2 = func (x,y) { see x+y+nl } call myfunc(3,4) Output: 7 7 39.4. Using “()” around the function parameters 284
324.
Ring Documentation, Release1.16 39.5 Using Semi-colon after and between statements In Ring we can use semi-colon after and between statements (optional). Example: # Using semi-colon is optional see "Hello" + nl ; see "How are you?" + nl ; see "Welcome to Ring" + nl ; one() ; two() ; three() ; func one ; see "one" + nl ; func two ; see "two" + nl ; func three ; see "three" + nl ; Output: Hello How are you? Welcome to Ring one two three 39.6 Using $ and @ in the start of the variable name You can use any unicode character in the variable name also we can use $ and @ in the name. This feature may help, for example we can start global variables with $ and the object attributes with @. In other languages like Ruby this is the rule, In the Ring language this is just an option without any force from the Compiler. example: $global_variable = 5 new test { hello() } class test @instance_variable = 10 func hello local_variable = 15 see "Global : " + $global_variable + nl + "Instance : " + @instance_variable + nl + "Local : " + local_variable + nl Output: Global : 5 Instance : 10 Local : 15 39.5. Using Semi-colon after and between statements 285
325.
Ring Documentation, Release1.16 39.7 Using the ‘elseif’ keyword as ‘but’ in if statement if you don’t like the ‘but’ keyword in if statement Then you can use the ‘elseif’ keyword. Example: give x if x = 1 see "one" elseif x=2 see "two" elseif x=3 see "three" elseif x=4 see "four" else see "other" ok see nl 39.8 Using the ‘else’ keyword as ‘other’ in switch statement if you don’t like the ‘other’ keyword in switch statement Then you can use the ‘else’ keyword. Also you can replace ‘else’ with ‘other’ in if statement. i.e. ‘other’ keyword is the same as ‘else’ keyword. Example: x = 1 switch x on 10 see "10" + nl else see "not 10" + nl end Output: not 10 39.9 Using the ‘end’ keyword in different control structures We can use the ‘end’ keyword to close different control structures • If statement • For loop • Switch • While • Try-Catch Example: 39.7. Using the ‘elseif’ keyword as ‘but’ in if statement 286
326.
Ring Documentation, Release1.16 see "if statement.." + nl x = 1 if x = 1 see "one" + nl elseif x=2 see "two" + nl elseif x=3 see "three" + nl end see "for loop.." + nl for t = 1 to 10 see t end see nl see "switch..." + nl x = 1 switch x on 1 see "one" + nl on 2 see "two" + nl end see "try catch..." + nl try x = 1 / 0 catch see "catching error" + nl end Output: if statement.. one for loop.. 12345678910 switch... one try catch... catching error 39.10 Using braces to start and end different control structures We can use braces { } to start and end different control structures • If statement • For loop • Switch • While • Try-Catch Example: 39.10. Using braces to start and end different control structures 287
327.
Ring Documentation, Release1.16 see "if statement.." + nl x = 1 if x = 1 { see "one" + nl elseif x=2 see "two" + nl elseif x=3 see "three" + nl } see "for loop.." + nl for t = 1 to 10 { see t } see nl see "switch..." + nl x = 1 switch x { on 1 see "one" + nl on 2 see "two" + nl } see "try catch..." + nl try { x = 1 / 0 catch see "catching error" + nl } Output: if statement.. one for loop.. 12345678910 switch... one try catch... catching error 39.11 Using ‘put’ and ‘get’ as ‘see’ and ‘give’ We can replace the ‘see’ keyword with the ‘put’ keyword. Also we can replace the ‘give’ keyword with the ‘get’ keyword. Example: put "Hello World" + nl put "Enter Your Name ? " Get Name Put "Hello " + Name 39.11. Using ‘put’ and ‘get’ as ‘see’ and ‘give’ 288
328.
Ring Documentation, Release1.16 39.12 Using ‘case’ as ‘on’ in switch statements We can replace the ‘on’ keyword with ‘case’ keyword in the switch statement. Example (1) : for x=1 to 10 switch x case 1 put "one" + nl case 2 put "two" + nl case 3 put "three" + nl else put "else" + nl end end Example (2) : for x=1 to 10 { switch x { case 1 put "one" + nl case 2 put "two" + nl case 3 put "three" + nl else put "else" + nl } } 39.13 Using ‘def’ as ‘func’ in functions/methods definition We can use the ‘def’ keyword as the ‘func’ keyword to define functions and methods. Example: one() two() def one put "one" + nl def two put "two" + nl 39.14 Using braces { } in Packages/Classes/Functions Example: load "stdlib.ring" import mypackage new myclass { myfunc() } package mypackage { class myclass { (continues on next page) 39.12. Using ‘case’ as ‘on’ in switch statements 289
329.
Ring Documentation, Release1.16 (continued from previous page) func myfunc { print("Hello, World!n") } } } 39.15 Using ‘end’ keyword after Packages/Classes/Functions Example: import mypackage new myclass { myfunc() } package mypackage class myclass def myfunc put "Hello, World!" end end end 39.16 Using ‘endpackage’/’endclass’/’endfunc’ keywords after Pack- ages/Classes/Functions Example: import mypackage new myclass { myfunc() } package mypackage class myclass func myfunc see "welcome" + nl endfunc endclass endpackage 39.15. Using ‘end’ keyword after Packages/Classes/Functions 290
330.
Ring Documentation, Release1.16 39.17 Ignore new lines after keywords Starting from Ring 1.8 the compiler will ignore new lines after keywords that expect tokens after it Example: see " Hello, World! " test() func #======================# Test #======================# ? " Hello from the Test function " Output: Hello, World! Hello from the Test function 39.17. Ignore new lines after keywords 291
331.
CHAPTER FORTY INTRODUCTION TO THETYPE HINTS LIBRARY In this chapter we will learn about the Type Hints Library 40.1 Why Type Hints? Using this library we can add the type information to the source code which will be very useful for tools like • Code Editors • Static-Analysis Note: Ring is a dynamic language, No type checking will be done by the compiler. 40.2 Example The next example will use the Type Hints library load "typehints.ring" see sum(3,4) + nl ; see sayHello("Mahmoud"); int func sum(int x,int y) { return x+y ; } string func sayHello(string name) { return "Hello " + name ; } 292
332.
Ring Documentation, Release1.16 40.3 User Types The Type Hints library is very powerful and will support user types (Classes) automatically Example: load "typehints.ring" import mypackage test() { main([:one,:two,:three]) } myclass func test() { see "Testing User Types!" + nl return new myclass } package mypackage { public class myclass { public static void func main(list args) { see "welcome" + nl see args } } } 40.4 Using Types inside Code Also you can use the types inside the code (not only the function prototype) Example: load "typehints.ring" int sum = sum(3,4) string msg = sayHello("Mahmoud") see "Sum = " + sum + nl + msg + nl int func sum(int x,int y) { return x+y ; } string func sayHello(string name) { return "Hello " + name ; } 40.3. User Types 293
333.
Ring Documentation, Release1.16 40.5 Rules • To use the types in the function prototype you must use ‘(‘ and ‘)’ around parameters • To use the types in the function code, You must set the variable value (Assignment). The next types are defined by the library # Low Level Types char unsigned signed int short long float double void # High Level Types string list number object # Other public static abstract protected override 40.5. Rules 294
334.
CHAPTER FORTYONE THE TRACE LIBRARYAND THE INTERACTIVE DEBUGGER In this chapter we will learn about the Trace Library and the Interactive Debugger 41.1 Loading the Trace library To start using the Trace library, We must load it first! load "tracelib.ring" 41.2 Trace All Events The next example demonstrates the Trace library usage to trace all events. # Trace All Events trace(:AllEvents) see "Hello, world!" + nl see "Welcome" + nl see "How are you?" +nl mytest() new myclass { mymethod() } func mytest see "Message from mytest" + nl class myclass func mymethod see "Message from mymethod" + nl 295
335.
Ring Documentation, Release1.16 41.3 Trace control flow between functions The next example demonstrates the Trace library usage to trace the control flow between functions. Trace(:Functions) test1() func test1 see :test1 + nl test2() func test2 see :test2 + nl see test3() + nl func test3 see :test3 + nl return "test 3 output" 41.4 Pass Error The next example demonstrates the Trace library usage to pass an error! Trace(:PassError) test1() func test1 x = 10 see :test1 + nl test2() # Runtime Error! see "We can continue!" 41.5 Interactive Debugger The next example demonstrates the Trace library usage to use the Interactive Debugger Trace(:Debugger) test1() see "good bye!" + nl func test1 x = 10 see :test1 + nl t = 12 test2() # Runtime Error! see "After Error!" +nl see "t = " see t see nl see "x = " see x see nl 41.3. Trace control flow between functions 296
336.
Ring Documentation, Release1.16 41.6 Execute Program Line by Line The next example demonstrates the Trace library usage to execute the program line by line! Trace(:LineByLine) test1() func test1 x = 10 see :test1 + nl t = 12 test2() see "After Error!" +nl see "t = " + t + nl 41.7 BreakPoint The next example demonstrates the Trace library usage to stop at a breakpoint! test1() func test1 x = 10 see :test1 + nl t = 12 BreakPoint() see "After breakpoint!" +nl see "t = " + t + nl see "End of program!" + nl 41.8 Disable BreakPoints The next example demonstrates the Trace library usage and how to disable the Breakpoints! NoBreakPoints() test1() func test1 x = 10 see :test1 + nl t = 12 BreakPoint() see "After breakpoint!" +nl see "t = " + t + nl see "End of program!" + nl 41.6. Execute Program Line by Line 297
337.
Ring Documentation, Release1.16 41.9 Using the Interactive Debugger The next example uses a Breakpoint to open the Interactive Debugger! load "tracelib.ring" test1() func test1 x = 10 see :test1 + nl t = 12 BreakPoint() see "After breakpoint!" +nl see "t = " + t + nl see "End of program!" + nl Screen Shots: We have the Interactive Debugger at the Breakpoint! We can print the variables values We can change the variables values then continue execution 41.9. Using the Interactive Debugger 298
338.
Ring Documentation, Release1.16 We can run the Interactive Debugger in the Output Window 41.9. Using the Interactive Debugger 299
339.
CHAPTER FORTYTWO EMBEDDING RING INRING In this chapter we will learn about embedding Ring in Ring programs and applications. 42.1 Embedding Ring in Ring without sharing the State From Ring 1.0 we already have functions for embedding Ring in the C language. Also we can execute Ring code inside Ring programs using the eval() function. In this release we provide functions for embedding Ring in Ring programs without sharing the state. Advantages: (1) Quick integration for Ring programs and applications together without conflicts. (2) Execute and run Ring code in safe environments that we can trace. Example: pState = ring_state_init() ring_state_runcode(pState,"See 'Hello, World!'+nl") ring_state_runcode(pState,"x = 10") pState2 = ring_state_init() ring_state_runcode(pState2,"See 'Hello, World!'+nl") ring_state_runcode(pState2,"x = 20") ring_state_runcode(pState,"see x +nl") ring_state_runcode(pState2,"see x +nl") v1 = ring_state_findvar(pState,"x") v2 = ring_state_findvar(pState2,"x") see v1[3] + nl see V2[3] + nl ring_state_delete(pState) ring_state_delete(pState2) Output: Hello, World! Hello, World! 10 20 (continues on next page) 300
340.
Ring Documentation, Release1.16 (continued from previous page) 10 20 42.2 Serial Execution of Programs We can execute application after another application using ring_state_main() Example: chdir(exefolder()+"/../applications/formdesigner") ring_state_main('formdesigner.ring') chdir(exefolder()+"/../applications/cards") ring_state_main('cards.ring') 42.3 ring_state_setvar() Using ring_state_setvar() we can set variables value The value could be (String, Number, List or C Pointer) We need this function to quickly pass lists and C pointers to the Sub Ring Environment Syntax: ring_state_setvar(oState,cVariableName,Value) Example: load "guilib.ring" myapp = null win = null func main myapp = new qApp { win = new qWidget() { setWindowTitle("Advanced Example on using ring_state_setvar() ˓ →") move(100,100) resize(600,400) new qPushButton(win) { setText("Test") setClickEvent("Test()") } # We need this because using load 'guilib.ring' in # the sub environment # Will create timers by Qt and closing the window # will not be enough to close the application oFilter = new qAllEvents(win) oFilter.setCloseEvent("myapp.quit()") win.installeventfilter(oFilter) show() } (continues on next page) 42.2. Serial Execution of Programs 301
341.
Ring Documentation, Release1.16 (continued from previous page) exec() } func test pState = ring_state_init() ring_state_runcode(pstate,"load 'guilib.ring'") ring_state_runcode(pState,"x = NULL") # Pass String ring_state_setvar(pState,"x","hello") ring_state_runcode(pState,"? x") # Pass Number ring_state_setvar(pState,"x",100) ring_state_runcode(pState,"? x") # Pass List ring_state_setvar(pState,"x",["one","two","three"]) ring_state_runcode(pState,"? x") # Pass Object # We can't pass the Ring Object (win) # Because Objects store pointers to the Class Information # And the class is related to the Parent Ring Environment # And the sub Ring environment can't access it # But we can pass C pointers like win.pObject ring_state_setvar(pState,"x",win.pObject) # Now we create the object again but using the same C pointer # So we have access to the Same window in the parent Ring environment ring_state_runcode(pState," new qWidget { pObject = x setwindowtitle('Message from the Sub Ring Environment ˓ →') } ") ring_state_delete(pState) 42.4 ring_state_new() and ring_state_mainfile() Using ring_state_new() and ring_state_mainfile() we can run Ring programs from Ring programs But unlike ring_state_main(), Here we can control when to delete the Ring state! This is important when we run GUI programs from GUI programs Because they will share the GUI Library (RingQt), And In this case the caller will call qApp.Exec() So the sub program, will not stop and will return to the Main program Here deleting the State of the sub programs will lead to a problem when we run the sub program events So keeping the state is important for sub GUI programs hosted in GUI programs. Example: load "guilib.ring" func main (continues on next page) 42.4. ring_state_new() and ring_state_mainfile() 302
342.
Ring Documentation, Release1.16 (continued from previous page) new qApp { win = new qWidget() { setWindowTitle("Test ring_state_mainfile()") resize(400,400) move(100,100) btn = new qPushButton(Win) { settext("test") setclickevent("mytest()") } show() } exec() } func mytest pState = ring_state_new() ring_state_mainfile(pState,"runprogram.ring") # Here we don't delete the state if we will run GUI application # So we can run the GUI application events // ring_state_delete(pState) If you will use this feature, remember to update the previous example based on your application needs So you can call ring_state_delete() at some point to avoid the memory leak! 42.5 Runtime Errors when Embedding Ring in Ring Starting from Ring 1.8 When embedding Ring in Ring, the error in the hosted environment will not close the host Example: ? "Start the test!" pState = ring_state_init() ring_state_runcode(pState," ? 'Let us try having an error' ? x") ring_state_delete(pState) ? "" ? "End of test!" Output: Start the test! Let us try having an error Line 1 Error (R24) : Using uninitialized variable : x in file Ring_EmbeddedCode End of test! 42.5. Runtime Errors when Embedding Ring in Ring 303
343.
Ring Documentation, Release1.16 42.6 ring_state_filetokens() function Starting from Ring 1.12 we have the ring_state_filetokens() function Using this function we can get all the tokens in the ring source code file. C_FILENAME = "test_tokens.ring" C_WIDTH = 12 # write the file write(C_FILENAME,' see "Hello, World!" ? 3*2+3 Name = "Ring" ? Name ') # Token Type C_KEYWORD = 0 C_OPERATOR = 1 C_LITERAL = 2 C_NUMBER = 3 C_IDENTIFIER = 4 C_ENDLINE = 5 # Keywords List aKEYWORDS = ["IF","TO","OR","AND","NOT","FOR","NEW","FUNC", "FROM","NEXT","LOAD","ELSE","SEE","WHILE","OK","CLASS","RETURN","BUT", "END","GIVE","BYE","EXIT","TRY","CATCH","DONE","SWITCH","ON","OTHER","OFF", "IN","LOOP","PACKAGE","IMPORT","PRIVATE","STEP","DO","AGAIN","CALL","ELSEIF", "PUT","GET","CASE","DEF","ENDFUNC","ENDCLASS","ENDPACKAGE", "CHANGERINGKEYWORD","CHANGERINGOPERATOR","LOADSYNTAX"] pState = ring_state_new() aList = ring_state_filetokens(pState,C_FILENAME) PrintTokens(aList) ring_state_delete(pState) func PrintTokens aList for aToken in aList switch aToken[1] on C_KEYWORD ? Width("Keyword",C_WIDTH) + ": " + aKeywords[0+aToken[2]] on C_OPERATOR ? Width("Operator",C_WIDTH) + ": " + aToken[2] on C_LITERAL ? Width("Literal",C_WIDTH) + ": " + aToken[2] on C_NUMBER ? Width("Number",C_WIDTH) + ": " + aToken[2] on C_IDENTIFIER ? Width("Identifier",C_WIDTH) + ": " + aToken[2] on C_ENDLINE ? "EndLine" off next func Width cText,nWidth return cText+copy(" ",nWidth-len(cText)) 42.6. ring_state_filetokens() function 304
344.
Ring Documentation, Release1.16 Output: EndLine Keyword : SEE Literal : Hello, World! EndLine Operator : ? Number : 3 Operator : * Number : 2 Operator : + Number : 3 EndLine Identifier : name Operator : = Literal : Ring EndLine Operator : ? Identifier : name EndLine 42.6. ring_state_filetokens() function 305
345.
CHAPTER FORTYTHREE STDLIB FUNCTIONS In thischapter we are going to learn about functions in the stdlib.ring Before using the functions in the library, We must load the library first load "stdlib.ring" Instead of using stdlib.ring we can use stdlibcore.ring Using stdlibcore.ring we can use the StdLib functions (Without Classes) This is useful when developing standalone console applications Because using stdlib.ring (functions & classes) will load libraries like RingLibCurl, RingOpenSSL, etc. 43.1 Puts() function print the value then print new line (nl) Syntax: puts(expr) Example: Load "stdlib.ring" Puts("Hello, World!") 43.2 Print() function print string - support n,t and r Also we can use #{variable_name} to insert variables values. Syntax: print(string) ---> String Example: 306
346.
Ring Documentation, Release1.16 print("nHello, WorldnnHow are you? tt I'm fine!n") x=10 y=20 print("nx value = #{x} , y value = #{y} n") 43.3 Print2Str() Function Syntax: print2Str(string) ---> String Example: world = "World!" mystring = print2str("Hello, #{world} nIn Year n#{2000+17} n") see mystring + nl Output: Hello, World! In Year 2017 43.4 GetString() function Get input from the keyboard - return value as string getstring() ---> string 43.5 GetNumber() function Get input from the keyboard - return value as number getnumber() ---> number 43.6 AppPath() function Get the path of the application folder Syntax: AppPath() ---> The path as String Example: 43.3. Print2Str() Function 307
347.
Ring Documentation, Release1.16 Load "stdlib.ring" # Application Path Puts("Test AppPath()") See AppPath() + nl 43.7 JustFilePath() function Get the path of the file, remove the file name. Syntax: JustFilePath(cFile) ---> The path as String Example: load "stdlib.ring" see justfilePath("b:ringapplicationsrnoternote.ring") Output: b:ringapplicationsrnote 43.8 JustFileName() function Get the file, remove the file path. Syntax: JustFileName(cFile) ---> The file name as String Example: load "stdlib.ring" see justfileName("b:ringapplicationsrnoternote.ring") Output: rnote.ring 43.7. JustFilePath() function 308
348.
Ring Documentation, Release1.16 43.9 Value() function create a copy from a list or object Syntax: value(List) ---> new list Example: Load "stdlib.ring" aList = 1:10 del(value(aList),1) # delete first item see aList # print numbers from 1 to 10 43.10 Times() function Execute a Function nCount times Syntax: Times(nCount,function) Example: Load "stdlib.ring" Puts("Test Times()") Times ( 3 , func { see "Hello, World!" + nl } ) 43.11 Map() function Execute a Function on each list item Syntax: Map(alist,function) ---> List Example: Load "stdlib.ring" Puts("Test Map()") See Map( 1:10, func x { return x*x } ) 43.9. Value() function 309
349.
Ring Documentation, Release1.16 43.12 Filter() function Execute a Function on each list item to filter items Syntax: Filter(alist,function) ---> List Example: Load "stdlib.ring" Puts("Test Filter()") See Filter( 1:10 , func x { if x <= 5 return true else return false ok } ) 43.13 Split() function Convert string words to list items Syntax: Split(cstring,delimiter) ---> List Example: Load "stdlib.ring" Puts("Test Split()") See Split("one two three four five"," ") 43.14 SplitMany() function Convert string words to list items. Allow many delimiters. Syntax: SplitMany(cstring,delimiters as string or list) --> List Example: Load "stdlib.ring" Puts("Test SplitMany()") See SplitMany("one,two,three,four and five"," ,") 43.12. Filter() function 310
350.
Ring Documentation, Release1.16 43.15 Capitalized() function Return a copy of a string with the first letter capitalized Syntax: Capitalized(string) ---> string Example: Load "stdlib.ring" Puts("Test Capitalized()") See capitalized("welcome to the Ring Programming Language") 43.16 IsSpecial() function Check whether a character is special or not Syntax: IsSpecial(char) ---> True/False Example: Load "stdlib.ring" Puts("Test Isspecial()") See "Isspecial = " + isSpecial("%") + nl 43.17 IsVowel() function Check whether a character is vowel or not Syntax: IsVowel(char) ---> True/False Example: Load "stdlib.ring" Puts("Test Isvowel()") See "Isvowel = " + isVowel("c") + nl 43.15. Capitalized() function 311
351.
Ring Documentation, Release1.16 43.18 LineCount() function Return the lines count in a text file. Syntax: LineCount(cFileName) ---> Lines Count as number Example: Load "stdlib.ring" Puts("Test Linecount()") See "the number of lines = " + lineCount("test.ring") 43.19 Factorial() function Return the factorial of a number Syntax: Factorial(number) ---> number Example: Load "stdlib.ring" Puts("Test Factorial()") see "6 factorial is : " + Factorial(6) 43.20 Fibonacci() function Return the fibonacci number Syntax: Fibonacci(number) ---> number Example: Load "stdlib.ring" Puts("Test Fibonacci()") see "6 Fibonacci is : " + Fibonacci(6) 43.18. LineCount() function 312
352.
Ring Documentation, Release1.16 43.21 IsPrime() function Check whether a number is prime or not Syntax: isprime(number) ---> Number Example: Load "stdlib.ring" Puts("Test Isprime()") if isPrime(16) see "16 is a prime number" else see "16 is not a prime number" ok 43.22 Sign() function Returns an integer value indicating the sign of a number. Syntax: Sign(number) ---> number ( -1 = negative , 0 , 1 (positive) ) Example: Load "stdlib.ring" Puts("Test Sign()") see "sign of 12 is = " + sign(12) + nl 43.23 List2File() function Write list items to text file (each item in new line). Syntax: List2File(aList,cFileName) Example: Load "stdlib.ring" # Test List2File Puts("Test List2File()") list2file(1:100,"myfile.txt") 43.21. IsPrime() function 313
353.
Ring Documentation, Release1.16 43.24 File2List() function Read text file and convert lines to list items Syntax: File2List(cFileName) ---> List Example: Load "stdlib.ring" # Test File2List Puts("Test File2List()") see len(file2list("myfile.txt")) 43.25 StartsWith() function Returns true if the given string starts with the specified substring. Leading white spaces are ignored. Syntax: StartsWith(string, substring) ---> True/False Example: Load "stdlib.ring" Puts("Test Startswith()") see Startswith("CalmoSoft", "Calmo") + nl 43.26 EndsWith() function Returns true if the given string ends with the specified substring. Trailing white spaces are ignored. Syntax: Endswith(string, substring) ---> True/False Example: Load "stdlib.ring" Puts("Test Endswith()") see endsWith("CalmoSoft", "Soft") + nl 43.24. File2List() function 314
354.
Ring Documentation, Release1.16 43.27 GCD() function Finding of the greatest common divisor of two integers. Syntax: Gcd(number,number) ---> number Example: Load "stdlib.ring" Puts("Test Gcd()") see gcd (24, 32) + nl 43.28 LCM() function Compute the least common multiple of two integers. Syntax: lcm(number,number) ---> number Example: Load "stdlib.ring" Puts("Test Lcm()") see Lcm(24,36) + nl 43.29 SumList() function Compute the sum of a list of integers. Syntax: sumlist(list) ---> number Example: Load "stdlib.ring" Puts("Test Sumlist()") aList = [1,2,3,4,5] see Sumlist(aList) + nl 43.27. GCD() function 315
355.
Ring Documentation, Release1.16 43.30 ProdList() function Compute the product of a list of integers. Syntax: prodlist(list) ---> number Example: Load "stdlib.ring" Puts("Test Prodlist()") aList = [1,2,3,4,5] see Prodlist(aList) + nl 43.31 EvenOrOdd() function Test whether an integer is even or odd. Result of test (1=odd 2=even). Syntax: evenorodd(number) ---> 1 (odd) or 2 (even) Example: Load "stdlib.ring" Puts("Test Evenorodd()") nr = 17 see Evenorodd(nr) + nl 43.32 Factors() function Compute the factors of a positive integer. Syntax: factors(number) ---> list Example: Load "stdlib.ring" Puts("Test Factors()") n = 45 aList = factors(n) see "Factors of " + n + " = " for i = 1 to len(aList) see "" + aList[i] + " " next 43.30. ProdList() function 316
356.
Ring Documentation, Release1.16 43.33 IsPalindrome() function Check if a sequence of characters is a palindrome or not. Syntax: IsPalindrome(String) ---> True/False Example: Load "stdlib.ring" Puts("Test IsPalindrome()") cString = "radar" see IsPalindrome(cString) 43.34 IsLeapYear() function Check whether a given year is a leap year in the Gregorian calendar. Syntax: Isleapyear(number) ---> True/False Example: Load "stdlib.ring" Puts("Test Isleapyear()") year = 2016 if Isleapyear(year) see "" + year + " is a leap year." else see "" + year + " is not a leap year." ok 43.35 BinaryDigits() function Compute the sequence of binary digits for a given non-negative integer. Syntax: binarydigits(number) ---> string Example: Load "stdlib.ring" Puts("Test Binarydigits()") b = 35 see "Binary digits of " + b + " = " + Binarydigits(b) 43.33. IsPalindrome() function 317
357.
Ring Documentation, Release1.16 43.36 MatrixMulti() function Multiply two matrices together. Syntax: Matrixmulti(List,List) ---> List Example: Load "stdlib.ring" # Multiply two matrices together. Puts("Test Matrixmulti()") A = [[1,2,3], [4,5,6], [7,8,9]] B = [[1,0,0], [0,1,0], [0,0,1]] see Matrixmulti(A, B) 43.37 MatrixTrans() function Transpose an arbitrarily sized rectangular Matrix. Syntax: Matrixtrans(List) ---> List Example: Load "stdlib.ring" # Transpose an arbitrarily sized rectangular Matrix. Puts("Test Matrixtrans()") matrix = [[78,19,30,12,36], [49,10,65,42,50], [30,93,24,78,10], [39,68,27,64,29]] see Matrixtrans(matrix) 43.38 DayOfWeek() function Return the day of the week of given date. (yyyy-mm-dd) Syntax: dayofweek(string) ---> string Example: Load "stdlib.ring" # Return the day of the week of given date. Puts("Test Dayofweek()") date = "2016-04-24" see "Data : " + date + " - Day : " + Dayofweek(date) + nl 43.36. MatrixMulti() function 318
358.
Ring Documentation, Release1.16 43.39 Permutation() function Generates all permutations of n different numerals. Syntax: permutation(list) Example: Load "stdlib.ring" # Generates all permutations of n different numerals Puts("Test Permutation()") list = [1, 2, 3, 4] for perm = 1 to 24 for i = 1 to len(list) see list[i] + " " next see nl Permutation(list) next 43.40 ReadLine() function Read line from file Syntax: readline(fp) ---> string Example: Load "stdlib.ring" # Read a file line by line. Puts("Test Readline()") fp = fopen("test.ring","r") while not feof(fp) See Readline(fp) end fclose(fp) 43.41 SubString() function Return a position of a substring starting from a given position in a string. Syntax: Substring(str,substr,npos) ---> string Example: 43.39. Permutation() function 319
359.
Ring Documentation, Release1.16 Load "stdlib.ring" # Return a position of a substring starting from a given position in a string. Puts("Test Substring()") a = "abcxyzqweabc" b = "abc" i = 4 see substring(a,b,i) 43.42 ChangeString() function Change substring from given position to a given position with another substring. Syntax: Changestring(cString, nPos1, nPos2, cSubstr) ---> cString Example: Load "stdlib.ring" # Change substring from given position for given position with a substring. Puts("Test Changestring()") see Changestring("Rmasdg",2,5,"in") # Ring 43.43 Sleep() function Sleep for the given amount of time. Syntax: sleep(nSeconds) Example: Load "stdlib.ring" Puts("Test Sleep()") see "Wait 3 Seconds!" Sleep(3) see nl 43.42. ChangeString() function 320
360.
Ring Documentation, Release1.16 43.44 IsMainSourceFile() function Check if the current file is the main source file Syntax: IsMainSourceFile() ---> True/False Example: Load "stdlib.ring" if ismainsourcefile() # code ok 43.45 MakeDir() function Make Directory Syntax: MakeDir(String) Example: Load "stdlib.ring" # Create Directory puts("create Directory : myfolder") makedir("myfolder") 43.46 Fsize() function The function return the file size in bytes. Syntax: FSize(File Handle) ---> Number (File Size in Bytes) 43.47 TrimAll() function Remove all spaces and tabs characters from a string Syntax: TrimAll(cString) ---> cString # Without Spaces and Tabs 43.44. IsMainSourceFile() function 321
361.
Ring Documentation, Release1.16 43.48 TrimLeft() function Remove all spaces and tabs characters from the left side of a string Syntax: TrimLeft(cString) ---> cString # Without Spaces and Tabs from the left side 43.49 TrimRight() function Remove all spaces and tabs characters from the right side of a string Syntax: TrimRight(cString) ---> cString # Without Spaces and Tabs from the right side 43.50 EpochTime() function Return the Epoch Time Syntax: EpochTime(cDate,cTime) ---> nEpochTime Example: see EpochTime( Date(), Time() ) 43.51 SystemCmd() Function We can execute system commands using the SystemCmd() function that outputs to a variable Syntax: SystemCmd(cCommand) Example: cYou = SystemCmd("whoami") # User Name logged in is output a variable cThem = SystemCmd("dir c:Users") # Directory List is output to a variable 43.48. TrimLeft() function 322
362.
Ring Documentation, Release1.16 43.52 ListAllFiles() Function Using this function we can quickly do a process on a group of files in a folder and it’s sub folders. Syntax: ListAllFiles(cFolder,cExtension) ---> List of Files Example: aList = ListAllFiles("c:/ring/ringlibs","ring") # *.ring only aList = sort(aList) see aList Example: see listallfiles("b:/ring/libraries/weblib","") # All Files 43.53 SystemSilent() Function We can execute system commands using the SystemSilent() function to avoid displaying the output! Syntax: SystemSilent(cCommand) 43.54 OSCreateOpenFolder() Function Create folder then change the current folder to this new folder Syntax: OSCreateOpenFolder(cCommand) 43.55 OSCopyFolder() Function Copy folder to the current folder Parameters : The path to the parent folder and the folder name to copy Syntax: OSCopyFolder(cParentFolder,cFolderName) Example To copy the folder b:ringringlibsstdlib to the current folder OSCopyFolder("b:ringringlibs","stdlib") 43.52. ListAllFiles() Function 323
363.
Ring Documentation, Release1.16 43.56 OSDeleteFolder() Function Delete Folder in the current Directory Syntax: OSDeleteFolder(cFolderName) 43.57 OSCopyFile() Function Copy File to the current directory Syntax: OSCopyFile(cFileName) 43.58 OSDeleteFile() Function Delete File Syntax: OSDeleteFile(cFileName) 43.59 OSRenameFile() Function Rename File Syntax: OSRenameFile(cOldFileName,cNewFileName) 43.60 List2Code() Function This function convert a Ring list during the runtime to Ring source code that we can save to source files. The list may contains strings, numbers or sub lists. Example: load "stdlibcore.ring" aList = 1:10 ? list2Code(aList) Output: [ 1,2,3,4,5,6,7,8,9,10 ] 43.56. OSDeleteFolder() Function 324
364.
Ring Documentation, Release1.16 43.61 Str2ASCIIList() Convert a string of bytes to a list of numbers where each item represent the ASCII code of one byte in the string. Syntax: Str2ASCIIList(String) ---> List of numbers 43.62 ASCIIList2Str() Convert a list of numbers where each item represent the ASCII code of one byte to a string of bytes. Syntax: ASCIIList2Str(List of numbers) ---> String Example: load "stdlibcore.ring" cStr = "MmMm" aList = Str2ASCIILIST(cStr) ? aList cStr2 = ASCIIList2Str(aList) ? cStr2 ? len(cStr2) Output: 77 109 77 109 MmMm 4 43.63 IsListContainsItems() Syntax: IsListContainsItems(aParent,aChild) ----> True/False Example: load "stdlibcore.ring" aList1 = "a":"z" aList2 = [:h,:l,:p,:u] ? IsListContainsItems(aList1,aList2) 43.61. Str2ASCIIList() 325
Ring Documentation, Release1.16 43.66 RandomList() Syntax: RandomList(aList) --> List contains the same items using Random order Example: load "stdlib.ring" aList = 1:5 ? RandomList(aList) 43.67 RandomItem() Pick an item from a list (Random Choice) Syntax: RandomItem(aList) --> Item Example: load "stdlib.ring" aList = 1:5 ? RandomItem(aList) 43.66. RandomList() 327
367.
CHAPTER FORTYFOUR STDLIB CLASSES In thischapter we are going to learn about the classes in the stdlib.ring • StdBase Class • String Class • List Class • Stack Class • Queue Class • HashTable Class • Tree Class • Math Class • DateTime Class • File Class • System Class • Debug Class • DataType Class • Conversion Class • ODBC Class • MySQL Class • SQLite Class • PostgreSQL Class • Security Class • Internet Class 328
368.
Ring Documentation, Release1.16 44.1 StdBase Class Attributes: • vValue : Object Value Methods: Method Description/Output Init(x) Set vValue Attribute to x value Print() Print vValue PrintLn() Print vValue then New Line Size() return number represent the size of vValue Value() return vValue Set(x) Call Init(x) 44.2 String Class Parent Class : StdBase Class Methods: Method Description/Output Init(String|Number|List) Lower() New String - Lower case characters Upper() New String - Upper case characters Left(x) New String - contains x characters from the left Right(x) New String - contains x characters from the right Lines() Number - Lines count Trim() New String - Remove Spaces Copy(x) New String - repeat string x times strcmp(cString) Compare string with cString tolist() List (String Lines to String Items) tofile(cFileName) Write string to file mid(nPos1,nPos2) New String - from nPos1 to nPos2 getfrom(nPos1) New String - from nPos1 to the end of the string replace(cStr1,cStr2,lCase) New String - Replace cStr1 with cStr2 , lCase (True=Match Case) split() List - Each Word as list item startswith(substring) Return true if the start starts with a substring endswith(substring) Return true if the start ends with a substring Example: Load "stdlib.ring" See "Testing the String Class" + nl oString = new string("Hello, World!") oString.println() oString.upper().println() oString.lower().println() oString.left(5).println() (continues on next page) 44.1. StdBase Class 329
369.
Ring Documentation, Release1.16 (continued from previous page) oString.right(6).println() oString = new string("Hi" + nl + "Hello" ) See oString.lines() + nl oString = new string(" Welcome ") oString.println() oString.trim().println() oString = new string("Hello! ") oString.copy(3).println() see oString.strcmp("Hello! ") + nl see oString.strcmp("Hello ") + nl see oString.strcmp("Hello!! ") + nl oString = new string(["one","two","three"]) oString.print() see oString.lines() + nl oString = new String(1234) oString.println() oString = new String("one"+nl+"two"+nl+"three") aList = oString.tolist() see "List Items" + nl See aList oString = new String( "Welcome to the Ring programming language") See "the - position : " + oString.pos("the") + nl oString = oString.getfrom(oString.pos("Ring")) oString.println() oString.mid(1,4).println() oString = oString.replace("Ring","***Ring***",true) oString.println() oString = oString.replace("ring","***Ring***",false) oString.println() oString1 = new string("First") oString2 = new string("Second") oString = oString1 + oString2 oString.println() oString = oString1 * 3 oString.println() for t in ostring see t next oString.tofile("test.txt") oString = new string("one two three") see nl see ostring.split() oString { set("Hello") println() set("How are you?") println() } Output: Testing the String Class Hello, World! HELLO, WORLD! hello, world! Hello World! 2 Welcome Welcome Hello! Hello! Hello! 0 (continues on next page) 44.2. String Class 330
370.
Ring Documentation, Release1.16 (continued from previous page) 1 -1 one two three 4 1234 List Items one two three the - position : 12 Ring programming language Ring ***Ring*** programming language ******Ring****** programming language FirstSecond FirstFirstFirst FirstFirstFirst one two three Hello How are you? 44.3 List Class Parent Class : StdBase Class Methods: Method Description/Output Init(String|List) Add(Value) Add item to the list Delete(nIndex) Delete item from the list Item(nIndex) Get item from the list First() Get the first item in the list Last() Get the last item in the list Set(nIndex,Value) Set item value FindInColumn(nCol,Value) Find item in a column Sort() Sort items - return new list Reverse() Reverse items - return new list Insert(nIndex,Value) Inset Item after nIndex example: Load "stdlib.ring" oList = new list ( [1,2,3] ) oList.Add(4) oList.print() see oList.item(1) + nl (continues on next page) 44.3. List Class 331
371.
Ring Documentation, Release1.16 (continued from previous page) oList.delete(4) oList.print() see oList.first() + nl see oList.last() + nl oList { set(1,"one") set(2,"two") set(3,"three") print() } see oList.find("two") + nl oList.sort().print() oList.reverse().print() oList.insert(2,"nice") oList.print() oList = new list ( [ [1,"one"],[2,"two"],[3,"three"] ] ) see copy("*",10) + nl oList.print() see "Search two : " + oList.findincolumn(2,"two") + nl see "Search 1 : " + oList.findincolumn(1,1) + nl oList = new list ( [ "Egypt" , "USA" , "KSA" ] ) for x in oList see x + nl next oList = new list ( [1,2,3,4] ) oList + [5,6,7] oList.print() oList = new list ( ["one","two"] ) oList2 = new list ( ["three","four"] ) oList + oList2 oList.print() output: 1 2 3 4 1 1 2 3 1 3 one two three 2 one three two three two one one two nice three ********** 1 one 2 (continues on next page) 44.3. List Class 332
372.
Ring Documentation, Release1.16 (continued from previous page) two 3 three Search two : 2 Search 1 : 1 Egypt USA KSA 1 2 3 4 5 6 7 one two three four 44.4 Stack Class Parent Class : List Class Methods: Method Description/Output Init(String|Number|List) Push(Value) Push item to the stack Pop() Pop item from the stack Print() Print the stack items example: Load "stdlib.ring" oStack = new Stack oStack.push(1) oStack.push(2) oStack.push(3) see oStack.pop() + nl see oStack.pop() + nl see oStack.pop() + nl oStack.push(4) see oStack.pop() + nl oStack { push("one") push("two") push("three") } oStack.print() output: 3 2 1 (continues on next page) 44.4. Stack Class 333
373.
Ring Documentation, Release1.16 (continued from previous page) 4 three two one 44.5 Queue Class Parent Class : List Class Methods: Method Description/Output Init(String|Number|List) Remove() Remove item from the Queue. example: Load "stdlib.ring" oQueue = new Queue oQueue.add(1) oQueue.add(2) oQueue.add(3) see oQueue.remove() + nl see oQueue.remove() + nl see oQueue.remove() + nl oQueue.add(4) see oQueue.remove() + nl oQueue { add("one") add("two") add("three") } oQueue.print() output: 1 2 3 4 one two three 44.6 HashTable Class Parent Class : List Class Methods: 44.5. Queue Class 334
374.
Ring Documentation, Release1.16 Method Description/Output Init(List) Add(cKey,Value) Add item to the HashTable Set(cKey,Value) Set item value using the Key GetValue(cKey) Get item value using the Key Contains(cKey) Check if the HashTable contains item using the Key Index(cKey) Get the item index using the Key example: Load "stdlib.ring" ohashtable = new hashtable See "Test the hashtable Class Methods" + nl ohashtable { Add("Egypt","Cairo") Add("KSA","Riyadh") see self["Egypt"] + nl see self["KSA"] + nl see contains("Egypt") + nl see contains("USA") + nl see index("KSA") + NL print() delete(index("KSA")) see copy("*",60) + nl print() } output: Test the hashtable Class Methods Cairo Riyadh 1 0 2 Egypt Cairo KSA Riyadh ************************************************************ Egypt Cairo 44.7 Tree Class Data: Attribute Description Data Node Value Children Children List Methods: 44.7. Tree Class 335
375.
Ring Documentation, Release1.16 Method Description/Output set(value) Set the node value. value() Get the node value. Add(value) Add new child. parent() Get the parent node. print() Print the tree nodes. example: Load "stdlib.ring" otree = new tree See "Test the tree Class Methods" + nl otree { set("The first step") # set the root node value see value() + nl Add("one") Add("two") Add("three") { Add("3.1") Add("3.2") Add("3.3") see children } see children oTree.children[2] { Add("2.1") Add("2.2") Add("2.3") { Add("2.3.1") Add("2.3.2") Add("test") } } oTree.children[2].children[3].children[3].set("2.3.3") } see copy("*",60) + nl oTree.print() output: Test the tree Class Methods The first step data: 3.1 parent: List... children: List... data: 3.2 parent: List... children: List... data: 3.3 parent: List... children: List... data: one parent: List... children: List... data: two parent: List... children: List... data: three parent: List... (continues on next page) 44.7. Tree Class 336
376.
Ring Documentation, Release1.16 (continued from previous page) children: List... ************************************************************ one two 2.1 2.2 2.3 2.3.1 2.3.2 2.3.3 three 3.1 3.2 3.3 44.8 Math Class Methods: Method Description sin(x) Returns the sine of an angle of x radians cos(x) Returns the cosine of an angle of x radians tan(x) Returns the tangent of an angle of x radians asin(x) Returns the principal value of the arc sine of x, expressed in radians acos(x) Returns the principal value of the arc cosine of x, expressed in radians atan(x) Returns the principal value of the arc tangent of x, expressed in radians atan2(y,x) Returns the principal arc tangent of y/x, in the interval [-pi,+pi] radians sinh(x) Returns the hyperbolic sine of x radians cosh(x) Returns the hyperbolic cosine of x radians tanh(x) Returns the hyperbolic tangent of x radians exp(x) Returns the value of e raised to the xth power log(x) Returns the natural logarithm of x log10(x) Returns the common logarithm (base-10 logarithm) of x ceil(x) Returns the smallest integer value greater than or equal to x floor(x) Returns the largest integer value less than or equal to x fabs(x) Returns the absolute value of x. pow(x,y) Returns x raised to the power of y sqrt(x) Returns the square root of x random(x) Returns a random number in the range [0,x] unsigned(n,n,c) Perform operation using unsigned numbers decimals(n) Determine the decimals digits after the point in float/double numbers example: Load "stdlib.ring" oMath = new Math See "Test the Math Class Methods" + nl See "Sin(0) = " + oMath.sin(0) + nl (continues on next page) 44.8. Math Class 337
377.
Ring Documentation, Release1.16 (continued from previous page) See "Sin(90) radians = " + oMath.sin(90) + nl See "Sin(90) degree = " + oMath.sin(90*3.14/180) + nl See "Cos(0) = " + oMath.cos(0) + nl See "Cos(90) radians = " + oMath.cos(90) + nl See "Cos(90) degree = " +oMath. cos(90*3.14/180) + nl See "Tan(0) = " + oMath.tan(0) + nl See "Tan(90) radians = " + oMath.tan(90) + nl See "Tan(90) degree = " + oMath.tan(90*3.14/180) + nl See "asin(0) = " + oMath.asin(0) + nl See "acos(0) = " + oMath.acos(0) + nl See "atan(0) = " + oMath.atan(0) + nl See "atan2(1,1) = " +oMath. atan2(1,1) + nl See "sinh(0) = " + oMath.sinh(0) + nl See "sinh(1) = " + oMath.sinh(1) + nl See "cosh(0) = " + oMath.cosh(0) + nl See "cosh(1) = " + oMath.cosh(1) + nl See "tanh(0) = " + oMath.tanh(0) + nl See "tanh(1) = " + oMath.tanh(1) + nl See "exp(0) = " + oMath.exp(0) + nl See "exp(1) = " + oMath.exp(1) + nl See "log(1) = " + oMath.log(1) + nl See "log(2) = " + oMath.log(2) + nl See "log10(1) = " + oMath.log10(1) + nl See "log10(2) = " + oMath.log10(2) + nl See "log10(10) = " + oMath.log10(10) + nl See "Ceil(1.12) = " + oMath.Ceil(1.12) + nl See "Ceil(1.72) = " + oMath.Ceil(1.72) + nl See "Floor(1.12) = " + oMath.floor(1.12) + nl See "Floor(1.72) = " + oMath.floor(1.72) + nl See "fabs(1.12) = " + oMath.fabs(1.12) + nl See "fabs(1.72) = " + oMath.fabs(1.72) + nl See "pow(2,3) = " + oMath.pow(2,3) + nl see "sqrt(16) = " + oMath.sqrt(16) + nl for x = 1 to 20 see "Random number Max (100) : " + oMath.random(100) + nl next x = 1.1234567890123 for d = 0 to 14 oMath.decimals(d) see x + nl next cKey = "hello" h = 0 (continues on next page) 44.8. Math Class 338
378.
Ring Documentation, Release1.16 (continued from previous page) for x in cKey h = oMath.unsigned(h,ascii(x),"+") h = oMath.unsigned(h,oMath.unsigned(h,10,"<<"),"+") r = oMath.unsigned(h,6,">>") h = oMath.unsigned(h, r,"^") next h = oMath.unsigned(h,oMath.unsigned(h,3,"<<"),"+") h = oMath.unsigned(h,oMath.unsigned(h,11,">>"),"^") h = oMath.unsigned(h,oMath.unsigned(h,15,"<<"),"+") see "Hash : " + h output: Test the Math Class Methods Sin(0) = 0 Sin(90) radians = 0.89 Sin(90) degree = 1.00 Cos(0) = 1 Cos(90) radians = -0.45 Cos(90) degree = 0.00 Tan(0) = 0 Tan(90) radians = -2.00 Tan(90) degree = 1255.77 asin(0) = 0 acos(0) = 1.57 atan(0) = 0 atan2(1,1) = 0.79 sinh(0) = 0 sinh(1) = 1.18 cosh(0) = 1 cosh(1) = 1.54 tanh(0) = 0 tanh(1) = 0.76 exp(0) = 1 exp(1) = 2.72 log(1) = 0 log(2) = 0.69 log10(1) = 0 log10(2) = 0.30 log10(10) = 1 Ceil(1.12) = 2 Ceil(1.72) = 2 Floor(1.12) = 1 Floor(1.72) = 1 fabs(1.12) = 1.12 fabs(1.72) = 1.72 pow(2,3) = 8 sqrt(16) = 4 Random number Max (100) : 87 Random number Max (100) : 49 Random number Max (100) : 99 Random number Max (100) : 58 Random number Max (100) : 15 Random number Max (100) : 46 Random number Max (100) : 37 Random number Max (100) : 64 (continues on next page) 44.8. Math Class 339
379.
Ring Documentation, Release1.16 (continued from previous page) Random number Max (100) : 73 Random number Max (100) : 35 Random number Max (100) : 89 Random number Max (100) : 80 Random number Max (100) : 20 Random number Max (100) : 33 Random number Max (100) : 44 Random number Max (100) : 89 Random number Max (100) : 82 Random number Max (100) : 94 Random number Max (100) : 83 Random number Max (100) : 68 1 1.1 1.12 1.123 1.1235 1.12346 1.123457 1.1234568 1.12345679 1.123456789 1.1234567890 1.12345678901 1.123456789012 1.1234567890123 1.12345678901230 Hash : 3372029979.00000000000000 44.9 DateTime Class Methods: Method Description/Output clock() The number of clock ticks from program start. time() Get the system time. date() Get the date. timelist() List contains the date and the time information. adddays(cDate,nDays) Return Date from cDate and after nDays diffdays(cDate1,cDate2) Return the Number of days (cDate1 - cDate2) example: Load "stdlib.ring" oDateTime = new datetime See "Test the datetime Class Methods" + nl See "Calculate performance" + nl t1 = oDateTime.clock() for x = 1 to 1000000 next (continues on next page) 44.9. DateTime Class 340
380.
Ring Documentation, Release1.16 (continued from previous page) see oDateTime.clock() - t1 + nl See "Time : " + oDateTime.time() + nl See "Date : " + oDateTime.date() + nl See oDateTime.TimeList() See "Month Name : " + oDateTime.TimeList()[4] cDate = oDateTime.date() see cDate + nl cDate = oDateTime.adddays(cDate,10) see cDate + nl cDate1 = oDateTime.date() see cDate1 + nl cDate2 = oDateTime.adddays(cDate1,10) see cDate2 + nl see "DiffDays = " + oDateTime.diffdays(cDate1,cDate2) + nl see "DiffDays = " + oDateTime.diffdays(cDate2,cDate1) + nl output: Test the datetime Class Methods Calculate performance 85 Time : 02:53:35 Date : 31/08/2016 Wed Wednesday Aug August 08/31/16 02:53:35 31 02 02 244 08 53 AM 35 35 3 08/31/16 02:53:35 16 2016 Arab Standard Time % Month Name : August31/08/2016 10/09/2016 31/08/2016 10/09/2016 DiffDays = -10 DiffDays = 10 44.9. DateTime Class 341
381.
Ring Documentation, Release1.16 44.10 File Class Methods: Method Description/Output read(cFileName) Read the file content write(cFileName,cStr) Write string to file dir(cFolderPath) Get the folder contents (files & sub folders) rename(cOld,cNew) Rename files using the Rename() function remove(cFileName) Delete a file using the Remove() function open(cFileName,cMode) Open a file using the Fopen() function close() Close file flush() Flushes the output buffer of a stream reopen(cFileName,cMode) Open another file using the same file handle tempfile() Creates a temp. file (binary). seek(noffset,nwhence) Set the file position of the stream tell() Know the current file position of a stream rewind() Set the file position to the beginning of the file getpos() Get handle to the current file position setpos(poshandle) Set the current file position clearerr() Clear the EOF error and the error indicators of a stream eof() Test the end-of-file indicator error() Test the error indicator perror(cErrorMessage) Print error message to the stderr getc() Get the next character from the stream gets(nsize) Read new line from the stream putc(cchar) Write a character to the stream puts(cStr) Write a string to the stream ungetc(cchar) Push a character to the stream fread(nsize) Read data from a stream fwrite(cString) Write data to a stream exists(cFileName) Check if a file exists example: Load "stdlib.ring" ofile = new file See "Test the file Class Methods" + nl see ofile.read(filename()) see nl ofile.open(filename(),"r") see ofile.gets(100) + nl ofile.close() 44.10. File Class 342
382.
Ring Documentation, Release1.16 44.11 System Class Methods: Method Description/Output system() Execute system commands sysget() Get environment variables ismsdos() Check if the operating system is MSDOS or not iswindows() Check if the operating system is Windows or not iswindows64() Check if the operating system is Windows 64bit or not isunix() Check if the operating system is Unix or not ismacosx() Check if the operating system is macOS or not islinux() Check if the operating system is Linux or not isfreebsd() Check if the operating system is FreeBSD or not isandroid() Check if the operating system is Android or not windowsnl() Get the windows new line string sysargv() Get the command line arguments passed to the ring script filename() Get the active source file example: Load "stdlib.ring" oSystem = new System See "Test the System Class Methods" + nl oSystem.system("dir") see oSystem.sysget("path") + nl see oSystem.ismsdos() + nl see oSystem.iswindows() + nl see oSystem.iswindows64() + nl see oSystem.isunix() + nl see oSystem.ismacosx() + nl see oSystem.islinux() + nl see oSystem.isfreebsd() + nl see oSystem.isandroid() + nl see oSystem.windowsnl() + nl see oSystem.sysargv() + nl see oSystem.filename() + nl 44.12 Debug Class Methods: Method Description/Output eval(cCode) Execute code during the runtime from string. raise(cError) Raise an exception. assert(cCondition) Test condition before executing the code. example: 44.11. System Class 343
383.
Ring Documentation, Release1.16 Load "stdlib.ring" oDebug = new Debug See "Test the Debug Class Methods" + nl oDebug.eval("see 'Hello'+nl") try x = 10 oDebug.assert(x=11) catch see "assert" + nl done raise("Error!") 44.13 DataType Class Methods: Method Description/Output isstring(vValue) We can know if the value is a string or not. isnumber(vValue) We can know if the value is a number or not. islist(vValue) We can know if the value is a list or not. type(vValue) Know the type of a value isnull(vValue) Check the value to know if it’s null or not. isalnum(vValue) 1 if the value is digit/letter or 0 if not isalpha(vValue) 1 if the value is a letter or 0 if not iscntrl(vValue) 1 if the value is a control character (no printing position) isdigit(vValue) 1 if the value is a digit or 0 if not isgraph(vValue) 1 if the value can be printed (Except space) or 0 if not islower(vValue) 1 if the value is lowercase letter or 0 if not isprint(vValue) 1 if the value occupies a printing position or 0 if not ispunct(vValue) 1 if the value is a punctuation character or 0 if not isspace(vValue) 1 if the value is a white-space or 0 if not isupper(vValue) 1 if the value is an uppercase alphabetic letter or 0 if not isxdigit(vValue) 1 if the value is a hexadecimal digit character or 0 if not example: Load "stdlib.ring" oDataType = new DataType See "Test the DataType Class Methods" + nl see oDataType.isstring("test") + nl see oDataType.isnumber(1) + nl see oDataType.islist(1:3) + nl see oDataType.type("test") + nl see oDataType.isnull(null) + nl see oDataType.isalnum("Hello") + nl + # print 1 oDataType.isalnum("123456") + nl + # print 1 oDataType.isalnum("ABCabc123") + nl + # print 1 oDataType.isalnum("How are you") + nl # print 0 because of spaces see oDataType.isalpha("Hello") + nl + # print 1 oDataType.isalpha("123456") + nl + # print 0 oDataType.isalpha("ABCabc123") + nl + # print 0 oDataType.isalpha("How are you") + nl # print 0 (continues on next page) 44.13. DataType Class 344
384.
Ring Documentation, Release1.16 (continued from previous page) See oDataType.iscntrl("hello") + nl + # print 0 oDataType.iscntrl(nl) # print 1 see oDataType.isdigit("0123456789") + nl + # print 1 oDataType.isdigit("0123a") + nl see oDataType.isgraph("abcdef") + nl + # print 1 oDataType.isgraph("abc def") + nl # print 0 see oDataType.islower("abcDEF") + nl + # print 0 oDataType.islower("ghi") + nl # print 1 see oDataType.isprint("Hello") + nl + # print 1 oDataType.isprint("Nice to see you") + nl + # print 1 oDataType.isprint(nl) + nl # print 0 see oDataType.isprint("Hello") + nl # print 1 see oDataType.isupper("welcome") + nl + # print 0 oDataType.isupper("WELCOME") + nl # print 1 see oDataType.isxdigit("0123456789abcdef") + nl + # print 1 oDataType.isxdigit("123z") # print 0 Output: Test the DataType Class Methods 1 1 1 STRING 1 1 1 1 0 1 0 0 0 0 11 0 1 0 0 1 1 1 0 1 0 1 1 0 44.13. DataType Class 345
385.
Ring Documentation, Release1.16 44.14 Conversion Class Methods: Method Description/Output number(vValue) Convert strings to numbers. string(vValue) Convert numbers to strings. ascii(vValue) Get the ASCII code for a letter. char(vValue) Convert the ASCII code to character. hex(vValue) Convert decimal to hexadecimal. dec(vValue) Convert hexadecimal to decimal. str2hex(vValue) Convert string characters to hexadecimal characters. hex2str(vValue) Convert hexadecimal characters to string. example: Load "stdlib.ring" oConversion = new conversion See "Test the conversion Class Methods" + nl See oConversion.number("3") + 5 + nl See oConversion.string(3) + "5" + nl See oConversion.Ascii("m") + nl See oConversion.char(77) + nl see oConversion.hex(162) + nl see oConversion.dec("a2") + nl cHex = oConversion.str2hex("Hello") see cHex + nl see oConversion.hex2str(cHex) + nl Output: Test the conversion Class Methods 8 35 109 M a2 162 48656c6c6f Hello 44.15 ODBC Class Methods: 44.14. Conversion Class 346
386.
Ring Documentation, Release1.16 Method Description/Output drivers() Get a list of ODBC drivers. datasources() Get a list of ODBC data sources. close() Free resources. connect(cConString) Connect to the database. disconnect() Close the connection. execute(cSQL) Execute SQL Statements colcount() Get columns count in the query result fetch() Fetch a row from the query result getdata(nCol) Get column value from the fetched row tables() Get a list of tables inside the database columns(cTableName) Get a list of columns inside the table autocommit(lStatus) Enable or disable the auto commit feature commit() Commit updates to the database rollback() Rollback updates to the database example: Load "stdlib.ring" oodbc = new odbc See "Test the odbc Class Methods" + nl oODBC { see drivers() see datasources() See "Connect to database" + nl see connect("DBQ=test.mdb;Driver={Microsoft Access Driver (*.mdb)}") + nl See "Select data" + nl see execute("select * from person") + nl nMax = colcount() See "Columns Count : " + nMax + nl while fetch() See "Row data:" + nl for x = 1 to nMax see getdata(x) + " - " next end See "Close database..." + nl disconnect() close() } 44.15. ODBC Class 347
387.
Ring Documentation, Release1.16 44.16 MySQL Class Methods: Method Description/Output info() Return string contains the MySQL Client version. error() Get the error message from the MySQL Client. connect(cServer,cUser,cPass,cDatabase) Connect to the MySQL database server. close() Close the connection to the MySQL database. query(cQuery) Execute SQL queries. insert_id() Get the inserted row id. result() Get the query result (data without column names). next_result() Move to the next query result. columns() Get a list of columns names. result2() Get all of the column names then the query result in one list. escape_string(cStr) Before storing binary data and special characters in the database. autocommit(lStatus) Enable or disable the auto commit feature. commit() Commit updates to the database. rollback() Rollback updates to the database. example: Load "stdlib.ring" omysql = new mysql See "Test the MySQL Class Methods" + nl omysql { see info() + nl connect("localhost", "root", "root","mahdb") see "Execute Query" + nl query("SELECT * FROM Employee") see "Print Result" + nl see result2() see "Close database" + nl close() } Output: Test the MySQL Class Methods 5.5.30 Execute Query Print Result Id Name Salary 1 Mahmoud 15000 2 Samir 16000 3 Fayed (continues on next page) 44.16. MySQL Class 348
388.
Ring Documentation, Release1.16 (continued from previous page) 17000 Close database 44.17 SQLite Class Methods: Method Description/Output open(cDatabase) Open Database. close() Close Database. errormessage() Get Error Message. execute(cSQL) Execute Query. example: Load "stdlib.ring" osqlite = new sqlite See "Test the sqlite Class Methods" + nl osqlite { open("test.db") sql = "CREATE TABLE COMPANY(" + "ID INT PRIMARY KEY NOT NULL," + "NAME TEXT NOT NULL," + "AGE INT NOT NULL," + "ADDRESS CHAR(50)," + "SALARY REAL );" execute(sql) sql = "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) " + "VALUES (1, 'Mahmoud', 29, 'Jeddah', 20000.00 ); " + "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) " + "VALUES (2, 'Ahmed', 27, 'Jeddah', 15000.00 ); " + "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)" + "VALUES (3, 'Mohammed', 31, 'Egypt', 20000.00 );" + "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)" + "VALUES (4, 'Ibrahim', 24, 'Egypt ', 65000.00 );" execute(sql) aResult = execute("select * from COMPANY") for x in aResult for t in x see t[2] + nl next next see copy("*",50) + nl for x in aResult see x["name"] + nl next close() } 44.17. SQLite Class 349
389.
Ring Documentation, Release1.16 Output: Test the sqlite Class Methods 1 Mahmoud 29 Jeddah 20000.0 2 Ahmed 27 Jeddah 15000.0 3 Mohammed 31 Egypt 20000.0 4 Ibrahim 24 Egypt 65000.0 ************************************************** Mahmoud Ahmed Mohammed Ibrahim 44.18 PostgreSQL Class Methods: Method Description/Output init(cConString) Open Database. close() Close Database. execute(cSQL) Execute Query. example: load "stdlib.ring" oPostgreSQL = new PostgreSQL("user=postgres password=sa dbname = mahdb") See "Test the PostgreSQL Class Methods" + nl oPostgreSQL { sql = "CREATE TABLE COMPANY_TEST(" + "ID INT PRIMARY KEY NOT NULL," + "NAME TEXT NOT NULL," + "AGE INT NOT NULL," + "ADDRESS CHAR(50)," + "SALARY REAL );" (continues on next page) 44.18. PostgreSQL Class 350
390.
Ring Documentation, Release1.16 (continued from previous page) execute(sql) sql = "INSERT INTO COMPANY_TEST (ID,NAME,AGE,ADDRESS,SALARY) " + "VALUES (1, 'Mahmoud', 29, 'Jeddah', 20000.00 ); " + "INSERT INTO COMPANY_TEST (ID,NAME,AGE,ADDRESS,SALARY) " + "VALUES (2, 'Ahmed', 27, 'Jeddah', 15000.00 ); " + "INSERT INTO COMPANY_TEST (ID,NAME,AGE,ADDRESS,SALARY)" + "VALUES (3, 'Mohammed', 31, 'Egypt', 20000.00 );" + "INSERT INTO COMPANY_TEST (ID,NAME,AGE,ADDRESS,SALARY)" + "VALUES (4, 'Ibrahim', 24, 'Egypt ', 65000.00 );" execute(sql) ? execute("select * from COMPANY_TEST") ? copy("*",50) close() } Output: Test the PostgreSQL Class Methods id name age address salary 1 Mahmoud 29 Jeddah 20000 2 Ahmed 27 Jeddah 15000 3 Mohammed 31 Egypt 20000 4 Ibrahim 24 Egypt 65000 ************************************************** 44.18. PostgreSQL Class 351
391.
Ring Documentation, Release1.16 44.19 Security Class Methods: Method Description/Output md5(cString) Calculate the MD5 hash. sha1(cString) Calculate the SHA1 hash. sha256(cString) Calculate the SHA256 hash. sha512(cString) Calculate the SHA512 hash. sha384(cString) Calculate the SHA384 hash. sha224(cString) Calculate the SHA224 hash. encrypt(cString,cKey,cIV) Encrypts the data using the Blowfish algorithm. decrypt(cString,cKey,cIV) Decrypt the data encrypted using the Encrypt() method. randbytes(nSize) Generate a string of pseudo-random bytes. example: Load "stdlib.ring" oSecurity = new security See "Test the security Class Methods" + nl oSecurity { see md5("hello") + nl + sha1("hello") + nl + sha256("hello") + nl + sha512("hello") + nl + sha384("hello") + nl + sha256("hello") + nl list = 0:15 cKey="" for x in list cKey += char(x) next list = 1:8 cIV = "" for x in list cIV += char(x) next cCipher = encrypt("hello",cKey,cIV) see cCipher + nl + decrypt(cCipher,cKey,cIV) + nl } 44.20 Internet Class Methods: • download(cURL) • sendemail(cSMTPServer,cEmail,cPassword,cSender,cReceiver,cCC,cTitle,cContent) example: Load "stdlib.ring" ointernet = new internet See "Test the internet Class Methods" + nl ointernet { see download("www.ring-lang.sf.net") } 44.19. Security Class 352
392.
CHAPTER FORTYFIVE DESKTOP, WEBASSEMBLY ANDMOBILE DEVELOPMENT USING RINGQT In this chapter we will learn how to use the Qt framework classes in our Ring applications to create Desktop, We- bAssembly and Mobile Applications. 45.1 The First GUI Application In this example we will create an application to ask the user about his/her name. When the user type the name in the textbox then click on “Say Hello” button, the textbox value will be updated by adding “Hello ” to the name. load "guilib.ring" oApp = new qApp { win1 = new qWidget() { setwindowtitle("Hello World") setGeometry(100,100,370,250) label1 = new qLabel(win1) { settext("What is your name ?") setGeometry(10,20,350,30) setalignment(Qt_AlignHCenter) } btn1 = new qPushButton(win1) { setGeometry(10,200,100,30) settext("Say Hello") setclickevent("pHello()") } btn2 = new qPushButton(win1) { setGeometry(150,200,100,30) settext("Close") setclickevent("pClose()") } lineedit1 = new qLineEdit(win1) { setGeometry(10,100,350,30) } show() (continues on next page) 353
393.
Ring Documentation, Release1.16 (continued from previous page) } exec() } Func pHello lineedit1.settext( "Hello " + lineedit1.text()) Func pClose oApp.quit() Program Output: At first we type the name in the textbox Then we click on the say hello button 45.1. The First GUI Application 354
394.
Ring Documentation, Release1.16 45.2 The Events Loop Qt uses Event-Driven and the events loop get the control when we call the exec() method from the qApp class. Once we call exec(), The events loop starts, and the Widgets starts responding to the different events (Mouse, Key- board, Timers, etc). You get the control back again when an event is fired and your callback function is called. Once the execution of your callback function is done, the control go back again to the events loop. Useful things to remember (1) We can do most of the work using normal events (Events provided directly by each widget). (2) We can add more events to any widget using the Events Filter. (3) Using Timers we can easily get the control back and check for more things to do. Also when our callback function is busy with doing time consuming operations, we can call the ProcessEvents() method from the qApp class to avoid stopping the GUI. oApp.processevents() We can avoid calling the exec() method, and create our main loop It’s not recommended to do that, It’s just an option. # Instead of calling the exec() method while true oApp.processevents() # Respond to GUI Events # More Thing to do, We have the control! # ..... end 45.3 Using Layout The next example is just an upgrade to the previous application to use the vertical layout. Load "guilib.ring" MyApp = New qApp { win1 = new qWidget() { setwindowtitle("Hello World") setGeometry(100,100,400,130) label1 = new qLabel(win1) { settext("What is your name ?") setGeometry(10,20,350,30) setalignment(Qt_AlignHCenter) } btn1 = new qpushbutton(win1) { setGeometry(10,200,100,30) settext("Say Hello") setclickevent("pHello()") } btn2 = new qpushbutton(win1) { (continues on next page) 45.2. The Events Loop 355
395.
Ring Documentation, Release1.16 (continued from previous page) setGeometry(150,200,100,30) settext("Close") setclickevent("pClose()") } lineedit1 = new qlineedit(win1) { setGeometry(10,100,350,30) } layout1 = new qVBoxLayout() { addwidget(label1) addwidget(lineedit1) addwidget(btn1) addwidget(btn2) } win1.setlayout(layout1) show() } exec() } Func pHello lineedit1.settext( "Hello " + lineedit1.text()) Func pClose MyApp.quit() The application during the runtime! 45.4 Using the QTextEdit Class In this example we will use the QTextEdit Class Load "guilib.ring" New qApp { win1 = new qWidget() { setwindowtitle("QTextEdit Class") setGeometry(100,100,500,500) (continues on next page) 45.4. Using the QTextEdit Class 356
396.
Ring Documentation, Release1.16 (continued from previous page) new qtextedit(win1) { setGeometry(10,10,480,480) } show() } exec() } During the runtime we can paste rich text in the qtextedit widget 45.4. Using the QTextEdit Class 357
397.
Ring Documentation, Release1.16 45.5 Using the QListWidget Class In this example we will use the QListWidget Class Load "guilib.ring" New qApp { win1 = new qWidget() { setGeometry(100,100,400,400) list1 = new qlistwidget(win1) { setGeometry(150,100,200,200) alist = ["one","two","three","four","five"] for x in alist additem(x) next setcurrentrow(3,2) win1.setwindowtitle("Items Count : " + count() ) } btn1 = new qpushbutton(win1) { setGeometry(10,200,100,30) settext("selected item") setclickevent("pWork()") } btn2 = new qpushbutton(win1) { setGeometry(10,240,100,30) settext("Delete item") setclickevent("pWork2()") } show() } exec() } func pWork btn1.settext(string(list1.currentrow())) func pWork2 list1 { takeitem(currentrow()) } The application during the runtime 45.5. Using the QListWidget Class 358
398.
Ring Documentation, Release1.16 Another Example: Load "guilib.ring" New qApp { win1 = new qWidget() { setGeometry(100,100,500,400) list1 = new qlistwidget(win1) { setGeometry(150,100,200,200) alist = ["one","two","three","four","five"] for x in alist additem(x) next setcurrentrow(3,2) win1.setwindowtitle("Items Count : " + count() ) } btn1 = new qpushbutton(win1) { setGeometry(10,200,100,30) settext("selected item") setclickevent("pWork()") } btn2 = new qpushbutton(win1) { setGeometry(10,240,100,30) (continues on next page) 45.5. Using the QListWidget Class 359
399.
Ring Documentation, Release1.16 (continued from previous page) settext("Delete item") setclickevent("pWork2()") } show() } exec() } func pWork nbrOfItems = list1.count() curItemNbr = list1.currentrow() curValue = list1.item(list1.currentrow()).text() win1.setwindowtitle( "After Select - NbrOfItems: " + nbrOfItems + " CurItemNbr: " + curItemNbr + " CurValue: " + curValue ) btn1.settext( string(list1.currentrow() ) + " --- " + list1.item(list1.currentrow()).text() ) func pWork2 list1 { takeitem(currentrow()) nbrOfItems = count() curItemNbr = currentrow() curValue = item(currentrow()).text() win1.setwindowtitle("After Delete - NbrOfItems: " + nbrOfItems + " CurItemNbr: " + curItemNbr +" CurValue: " + curValue ) } 45.6 Using QTreeView and QFileSystemModel In this example we will learn how to use the QTreeView widget to represent the File System Load "guilib.ring" New qApp { win1 = New qWidget() { setwindowtitle("Using QTreeView and QFileSystemModel") setGeometry(100,100,500,400) New qtreeview(win1) { setGeometry(00,00,500,400) oDir = new QDir() ofile = new QFileSystemModel() ofile.setrootpath(oDir.currentpath()) (continues on next page) 45.6. Using QTreeView and QFileSystemModel 360
400.
Ring Documentation, Release1.16 (continued from previous page) setmodel(ofile) } show() } exec() } The application during the runtime 45.7 Using QTreeWidget and QTreeWidgetItem In this example we will learn about using the QTreeWidget and QTreeWidgetItem classes Load "guilib.ring" New qApp { win1 = new qWidget() { setwindowtitle("TreeWidget") setGeometry(100,100,400,400) (continues on next page) 45.7. Using QTreeWidget and QTreeWidgetItem 361
401.
Ring Documentation, Release1.16 (continued from previous page) layout1 = new qvboxlayout() tree1 = new qtreewidget(win1) { setGeometry(00,00,400,400) setcolumncount(1) myitem = new qtreewidgetitem() myitem.settext(0,"The First Step") addtoplevelitem(myitem) for x = 1 to 10 myitem2 = new qtreewidgetitem() myitem2.settext(0,"hello"+x) myitem.addchild(myitem2) for y = 1 to 10 myitem3 = new qtreewidgetitem() myitem3.settext(0,"hello"+x) myitem2.addchild(myitem3) next next setheaderlabel("Steps Tree") } layout1.addwidget(tree1) setlayout(layout1) show() } exec() } The application during the runtime 45.7. Using QTreeWidget and QTreeWidgetItem 362
402.
Ring Documentation, Release1.16 45.8 Using QComboBox Class In this example we will learn about using the QComboBox class Load "guilib.ring" New qApp { win1 = new qWidget() { setwindowtitle("Using QComboBox") setGeometry(100,100,400,400) New QComboBox(win1) { setGeometry(150,100,200,30) alist = ["one","two","three","four","five"] for x in aList additem(x,0) next } show() } exec() } The application during the runtime 45.8. Using QComboBox Class 363
403.
Ring Documentation, Release1.16 45.9 Creating Menubar In this example we will learn about using the QMenuBar class Load "guilib.ring" MyApp = New qApp { win1 = new qWidget() { setwindowtitle("Using QMenubar") setGeometry(100,100,400,400) menu1 = new qmenubar(win1) { sub1 = addmenu("File") sub2 = addmenu("Edit") sub3 = addmenu("Help") sub1 { oAction = new qAction(win1) { settext("New") } addaction(oAction) oAction = new qAction(win1) { settext("Open") } (continues on next page) 45.9. Creating Menubar 364
404.
Ring Documentation, Release1.16 (continued from previous page) addaction(oAction) oAction = new qAction(win1) { settext("Save") } addaction(oAction) oAction = new qAction(win1) { settext("Save As") } addaction(oAction) addseparator() oAction = new qaction(win1) { settext("Exit") setclickevent("myapp.quit()") } addaction(oAction) } sub2 { oAction = new qAction(win1) { settext("Cut") } addaction(oAction) oAction = new qAction(win1) { settext("Copy") } addaction(oAction) oAction = new qAction(win1) { settext("Paste") } addaction(oAction) addseparator() oAction = new qAction(win1) { settext("Select All") } addaction(oAction) } sub3 { oAction = new qAction(win1) { settext("Reference") } addaction(oAction) sub4 = addmenu("Sub Menu") sub4 { oAction = new qAction(win1) { settext("Website") } addaction(oAction) oAction = new qAction(win1) { settext("Forum") } addaction(oAction) oAction = new qAction(win1) { settext("Blog") } addaction(oAction) } addseparator() oAction = new qAction(win1) { (continues on next page) 45.9. Creating Menubar 365
405.
Ring Documentation, Release1.16 (continued from previous page) settext("About") } addaction(oAction) } } show() } exec() } The application during the runtime 45.10 Context Menu Example: load "guilib.ring" new qApp { win = new qwidget() { setwindowtitle("Context Menu") resize(400,400) myfilter = new qAllEvents(win) { setContextmenuEvent("mymenu()") (continues on next page) 45.10. Context Menu 366
406.
Ring Documentation, Release1.16 (continued from previous page) } installeventfilter(myfilter) show() } exec() } func mymenu new qMenu(win) { oAction = new qAction(win) { settext("new") setClickEvent("See :New") } addaction(oAction) oAction = new qAction(win) { settext("open") setClickEvent("See :Open") } addaction(oAction) oAction = new qAction(win) { settext("save") setClickEvent("See :Save") } addaction(oAction) oAction = new qAction(win) { settext("close") setClickEvent("See :Close") } addaction(oAction) oCursor = new qCursor() exec(oCursor.pos()) } 45.11 Creating Toolbar In this example we will learn about using the QToolBar class Load "guilib.ring" New qApp { win1 = new qMainWindow() { setwindowtitle("Using QToolbar") setGeometry(100,100,600,400) abtns = [ new qpushbutton(win1) { settext("Add") } , new qpushbutton(win1) { settext("Edit") } , new qpushbutton(win1) { settext("Find") } , new qpushbutton(win1) { settext("Delete") } , new qpushbutton(win1) { settext("Exit") (continues on next page) 45.11. Creating Toolbar 367
407.
Ring Documentation, Release1.16 (continued from previous page) setclickevent("win1.close()") ˓ →} ] tool1 = new qtoolbar(win1) { for x in abtns addwidget(x) addseparator() next setmovable(true) setGeometry(0,0,500,30) setFloatable(true) } show() } exec() } The application during the runtime 45.11. Creating Toolbar 368
408.
Ring Documentation, Release1.16 45.12 Creating StatusBar In this example we will learn about using the QStatusBar class Load "guilib.ring" New qApp { win1 = new qMainWindow() { setwindowtitle("Using QStatusbar") setGeometry(100,100,400,400) status1 = new qstatusbar(win1) { showmessage("Ready!",0) } setstatusbar(status1) show() } exec() } The application during the runtime 45.12. Creating StatusBar 369
409.
Ring Documentation, Release1.16 45.13 Using QDockWidget In this example we will learn about using the QDockWidget class Load "guilib.ring" New qApp { win1 = new qMainWindow() { setwindowtitle("QDockWidget") setGeometry(100,100,400,400) label1 = new qlabel(win1) { settext("Hello") setGeometry(300,300,100,100) } label2 = new qlabel(win1) { settext("How are you ?") setGeometry(100,100,100,100) } dock1 = new qdockwidget(win1,0) { setwidget(label1) SetAllowedAreas(1) } dock2 = new qdockwidget(win1,0) { setwidget(label2) SetAllowedAreas(2) } adddockwidget(Qt_LeftDockWidgetArea,dock1,Qt_Horizontal) adddockwidget(Qt_LeftDockWidgetArea,dock2,Qt_Vertical) show() } exec() } The application during the runtime 45.13. Using QDockWidget 370
410.
Ring Documentation, Release1.16 45.14 Using QTabWidget In this example we will learn about using the QTabWidget class Load "guilib.ring" New qApp { win1 = new qMainWindow() { setwindowtitle("Using QTabWidget") setGeometry(100,100,400,400) page1 = new qwidget() { new qpushbutton(page1) { settext("The First Page") } } page2 = new qwidget() { new qpushbutton(page2) { settext("The Second Page") } } (continues on next page) 45.14. Using QTabWidget 371
411.
Ring Documentation, Release1.16 (continued from previous page) page3 = new qwidget() { new qpushbutton(page3) { settext("The Third Page") } } tab1 = new qtabwidget(win1) { inserttab(0,page1,"Page 1") inserttab(1,page2,"Page 2") inserttab(2,page3,"Page 3") setGeometry(100,100,400,400) } status1 = new qstatusbar(win1) { showmessage("Ready!",0) } setstatusbar(status1) showMaximized() } exec() } The application during the runtime 45.14. Using QTabWidget 372
412.
Ring Documentation, Release1.16 45.15 Using QTableWidget In this example we will learn about using the QTableWidget class Load "guilib.ring" New qApp { win1 = new qMainWindow() { setGeometry(100,100,1100,370) setwindowtitle("Using QTableWidget") Table1 = new qTableWidget(win1) { setrowcount(10) setcolumncount(10) setGeometry(0,0,800,400) setselectionbehavior(QAbstractItemView_SelectRows) for x = 1 to 10 for y = 1 to 10 item1 = new qtablewidgetitem("R"+X+"C"+Y) setitem(x-1,y-1,item1) next next } setcentralwidget(table1) show() } exec() } The application during the runtime 45.15. Using QTableWidget 373
413.
Ring Documentation, Release1.16 45.16 Using QProgressBar In this example we will learn about using the QProgressBar class Load "guilib.ring" New qApp { win1 = new qMainWindow() { setGeometry(100,100,600,150) setwindowtitle("Using QProgressBar") for x = 10 to 100 step 10 new qprogressbar(win1) { setGeometry(100,x,350,30) setvalue(x) } next show() } exec() } The application during the runtime 45.17 Using QSpinBox In this example we will learn about using the QSpinBox class Load "guilib.ring" New qApp { win1 = new qMainWindow() { setGeometry(100,100,450,260) setwindowtitle("Using QSpinBox") new qspinbox(win1) { setGeometry(50,100,350,30) setvalue(50) } show() (continues on next page) 45.16. Using QProgressBar 374
414.
Ring Documentation, Release1.16 (continued from previous page) } exec() } The application during the runtime 45.18 Using QSlider In this example we will learn about using the QSlider class Load "guilib.ring" New qApp { win1 = new qMainWindow() { setGeometry(100,100,500,400) setwindowtitle("Using QSlider") new qslider(win1) { setGeometry(100,100,50,130) settickinterval(50) } new qslider(win1) { setGeometry(100,250,250,30) settickinterval(50) setorientation(Qt_Horizontal) } show() } (continues on next page) 45.18. Using QSlider 375
415.
Ring Documentation, Release1.16 (continued from previous page) exec() } The application during the runtime 45.19 Using QDateEdit In this example we will learn about using the QDateEdit class Load "guilib.ring" New qApp { win1 = new qMainWindow() { setwindowtitle("Using QDateEdit") setGeometry(100,100,250,100) new qdateedit(win1) { setGeometry(20,40,220,30) } show() } exec() } 45.19. Using QDateEdit 376
416.
Ring Documentation, Release1.16 The application during the runtime 45.20 Using QDial In this example we will learn about using the QDial class Load "guilib.ring" New qApp { win1 = new qMainWindow() { setGeometry(100,100,450,500) setwindowtitle("Using QDial") new qdial(win1) { setGeometry(100,100,250,300) } show() } exec() } The application during the runtime 45.20. Using QDial 377
417.
Ring Documentation, Release1.16 Another Example Load "guilib.ring" New qApp { win1 = new qMainWindow() { setGeometry(100,100,450,500) setwindowtitle("Using QDial") button1 = new QPushButton(win1){ setGeometry(100,350,100,30) settext("Increment") setClickEvent("pIncrement()") } button2 = new QPushButton(win1){ setGeometry(250,350,100,30) settext("Decrement") setClickEvent("pDecrement()") } (continues on next page) 45.20. Using QDial 378
Ring Documentation, Release1.16 45.21 Using QWebView In this example we will learn about using the QWebView class Load "guilib.ring" New qApp { win1 = new qMainWindow() { setwindowtitle("QWebView") myweb = new qwebview(win1) { setGeometry(10,10,600,600) loadpage(new qurl("http://google.com")) } setcentralwidget(myweb) showMaximized() } exec() } 45.21. Using QWebView 380
420.
Ring Documentation, Release1.16 The application during the runtime 45.22 Using QCheckBox In this example we will learn about using the QCheckBox class Load "guilib.ring" New qApp { win1 = new qMainWindow() { setwindowtitle("Using QCheckBox") new qcheckbox(win1) { setGeometry(100,100,100,30) settext("New Customer!") } showMaximized() } exec() } The application during the runtime 45.22. Using QCheckBox 381
421.
Ring Documentation, Release1.16 Another Example: Load "guilib.ring" New qApp { win1 = new qMainWindow() { setGeometry(100,100,400,300) setwindowtitle("Using QCheckBox") ### 0-Unchecked 1-Checked CheckBox = new qcheckbox(win1) { setGeometry(100,100,160,30) settext("New Customer!") setclickedEvent("HandleClickEvent()") } show() } exec() } Func HandleClickEvent if CheckBox.isChecked() = 1 CheckBox.settext("New Customer. Check 1-ON") else CheckBox.settext("New Customer. Check 0-OFF") ok 45.22. Using QCheckBox 382
422.
Ring Documentation, Release1.16 45.23 Using QRadioButton and QButtonGroup In this example we will learn about using the QRadioButton and QButtonGroup classes Load "guilib.ring" New qApp { win1 = new qMainWindow() { setwindowtitle("Using QRadioButton") new qradiobutton(win1) { setGeometry(100,100,100,30) settext("One") } new qradiobutton(win1) { setGeometry(100,150,100,30) settext("Two") } new qradiobutton(win1) { setGeometry(100,200,100,30) settext("Three") } group2 = new qbuttongroup(win1) { btn4 = new qradiobutton(win1) { setGeometry(200,150,100,30) settext("Four") } btn5 = new qradiobutton(win1) { setGeometry(200,200,100,30) settext("Five") } addbutton(btn4,0) addbutton(btn5,0) } showMaximized() } exec() } The application during the runtime 45.23. Using QRadioButton and QButtonGroup 383
423.
Ring Documentation, Release1.16 45.24 Adding Hyperlink to QLabel In this example we will learn about creating Hyperlink using the QLabel class Load "guilib.ring" New qApp { win1 = new qMainWindow() { setwindowtitle("QLabel - Hyperlink") new qlabel(win1) { setGeometry(100,100,100,30) setopenexternallinks(true) settext('<a href="http://google.com">Google</a>') } showMaximized() } exec() } The application during the runtime 45.24. Adding Hyperlink to QLabel 384
424.
Ring Documentation, Release1.16 45.25 QVideoWidget and QMediaPlayer In this example we will learn about using the QVideoWidget and QMediaPlayer classes to play a group of movies from different positions at the same time Load "guilib.ring" New qApp { win1 = new qMainWindow() { setwindowtitle("QVideoWidget") btn1 = new qpushbutton(win1) { setGeometry(0,0,100,30) settext("play") setclickevent("player.play() player2.play() player3.play() player4.play()") } videowidget = new qvideowidget(win1) { setGeometry(50,50,600,300) setstylesheet("background-color: black") } videowidget2 = new qvideowidget(win1) { setGeometry(700,50,600,300) setstylesheet("background-color: black") } videowidget3 = new qvideowidget(win1) { setGeometry(50,370,600,300) setstylesheet("background-color: black") } (continues on next page) 45.25. QVideoWidget and QMediaPlayer 385
425.
Ring Documentation, Release1.16 (continued from previous page) videowidget4 = new qvideowidget(win1) { setGeometry(700,370,600,300) setstylesheet("background-color: black") } player = new qmediaplayer() { setmedia(new qurl("1.mp4")) setvideooutput(videowidget) setposition(35*60*1000) } player2 = new qmediaplayer() { setmedia(new qurl("2.mp4")) setvideooutput(videowidget2) setposition(23*60*1000) } player3 = new qmediaplayer() { setmedia(new qurl("3.mp4")) setvideooutput(videowidget3) setposition(14.22*60*1000) } player4 = new qmediaplayer() { setmedia(new qurl("4.avi")) setvideooutput(videowidget4) setposition(8*60*1000) } showfullscreen() } exec() } The application during the runtime 45.25. QVideoWidget and QMediaPlayer 386
426.
Ring Documentation, Release1.16 45.26 Using QFrame In this example we will learn about using the QFrame class Load "guilib.ring" New qApp { win1 = new qMainWindow() { setwindowtitle("Using QFrame") for x = 0 to 10 frame1 = new qframe(win1,0) { setGeometry(100,20+50*x,400,30) setframestyle(QFrame_Raised | QFrame_WinPanel) } next showMaximized() } exec() } The application during the runtime 45.26. Using QFrame 387
427.
Ring Documentation, Release1.16 45.27 Display Image using QLabel In this example we will learn about displaying an image using the QLabel widget Load "guilib.ring" New qApp { win1 = new qMainWindow() { setwindowtitle("QLabel - Display image") new qlabel(win1) { image = new qpixmap("b:/mahmoud/photo/advice.jpg") setpixmap(image) setGeometry(0,0,image.width(),image.height()) (continues on next page) 45.27. Display Image using QLabel 388
428.
Ring Documentation, Release1.16 (continued from previous page) } showMaximized() } exec() } The application during the runtime 45.27. Display Image using QLabel 389
429.
Ring Documentation, Release1.16 45.28 Menubar and StyleSheet Example In this example we will learn about creating menubar and setting the window stylesheet Load "guilib.ring" New qApp { win1 = new qMainWindow() { setwindowtitle("Menubar") menu1 = new qmenubar(win1) { sub1 = addmenu("File") sub1 { oAction = new qAction(win1) { settext("New") setenabled(false) } addaction(oAction) oAction = new qAction(win1) { settext("Open") setcheckable(true) setchecked(true) setstatustip("open new file") } addaction(oAction) oAction = new qAction(win1) { settext("Save") } addaction(oAction) oAction = new qAction(win1) { settext("Save As") } addaction(oAction) addseparator() oAction = new qaction(win1) oAction.settext("Exit") oAction.setclickevent("myapp.quit()") addaction(oAction) } } status1 = new qstatusbar(win1) { showmessage("Ready!",0) } setmenubar(menu1) setmousetracking(true) setstatusbar(status1) setStyleSheet("color: black; selection-color: black; selection-background-color:white ; background: QLinearGradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #eef, stop: 1 #ccf);") showmaximized() } exec() (continues on next page) 45.28. Menubar and StyleSheet Example 390
430.
Ring Documentation, Release1.16 (continued from previous page) } The application during the runtime 45.29 QLineEdit Events and QMessageBox In this example we will learn about using QLineEdit Events and displaying a Messagebox Load "guilib.ring" MyApp = New qApp { win1 = new qWidget() { setwindowtitle("Welcome") setGeometry(100,100,400,300) label1 = new qLabel(win1) { settext("What is your name ?") setGeometry(10,20,350,30) setalignment(Qt_AlignHCenter) } btn1 = new qpushbutton(win1) { setGeometry(10,200,100,30) settext("Say Hello") setclickevent("pHello()") } btn1 = new qpushbutton(win1) { setGeometry(150,200,100,30) settext("Close") setclickevent("pClose()") } (continues on next page) 45.29. QLineEdit Events and QMessageBox 391
431.
Ring Documentation, Release1.16 (continued from previous page) lineedit1 = new qlineedit(win1) { setGeometry(10,100,350,30) settextchangedevent("pChange()") setreturnpressedevent("penter()") } show() } exec() } Func pHello lineedit1.settext( "Hello " + lineedit1.text()) Func pClose MyApp.quit() Func pChange win1 { setwindowtitle( lineedit1.text() ) } Func pEnter new qmessagebox(win1) { setwindowtitle("Thanks") settext("Hi " + lineedit1.text() ) setstylesheet("background-color : white") show() } The application during the runtime 45.29. QLineEdit Events and QMessageBox 392
432.
Ring Documentation, Release1.16 45.30 Other Widgets Events Each Qt signal can be used in RingQt, just add Set before the signal name and add event after the signal name to get the method that can be used to determine the event code. For example the QProgressBar class contains a signal named valueChanged() To use it just use the function setVal- ueChangedEvent() Example: Load "guilib.ring" New qApp { win1 = new qMainWindow() { setwindowtitle("QProgressBar valueChanged Event") progress1 = new qprogressbar(win1) { setGeometry(100,100,350,30) setvalue(10) setvaluechangedevent("pChange()") } new qpushbutton(win1) { setGeometry(10,10,100,30) settext("increase") setclickevent("pIncrease()") } showMaximized() } (continues on next page) 45.30. Other Widgets Events 393
433.
Ring Documentation, Release1.16 (continued from previous page) exec() } func pIncrease progress1 { setvalue(value()+1) } func pchange win1.setwindowtitle("value : " + progress1.value() ) The application during the runtime Another example for the stateChanged event of the QCheckBox class Load "guilib.ring" New qApp { win1 = new qMainWindow() { setwindowtitle("QCheckBox") new qcheckbox(win1) { setGeometry(100,100,100,30) settext("New Customer!") setstatechangedevent("pchange()") } showMaximized() } exec() } Func pChange new qMessageBox(Win1) { setWindowTitle("Checkbox") settext("State Changed!") show() } The application during the runtime 45.30. Other Widgets Events 394
434.
Ring Documentation, Release1.16 45.31 Using the QTimer Class In this example we will learn about using the QTimer class Load "guilib.ring" new qApp { win1 = new qwidget() { setgeometry(100,100,200,70) setwindowtitle("Timer") label1 = new qlabel(win1) { setgeometry(10,10,200,30) settext(thetime()) } new qtimer(win1) { setinterval(1000) settimeoutevent("pTime()") start() } show() } exec() } func ptime label1.settext(thetime()) Func thetime return "Time : " + Time() The application during the runtime 45.31. Using the QTimer Class 395
435.
Ring Documentation, Release1.16 45.32 Using QProgressBar and Timer In this example we will learn about using the “animated” QProgressBar class and Timer ###------------------------------------ ### ProgressBar and Timer Example Load "guilib.ring" new qApp { win1 = new qwidget() { setgeometry(100,100,400,100) setwindowtitle("Timer and ProgressBar") LabelMan = new qlabel(win1) { setgeometry(10,10,200,30) settext(theTime()) ### ==>> func } TimerMan = new qtimer(win1) { setinterval(1000) settimeoutevent("pTime()") ### ==>> func start() } BarMan = new qprogressbar(win1) { setGeometry(100,50,300,10) ### Position X y, Length, Thickness setvalue(0) ### Percent filled } show() } exec() } func pTime LabelMan.settext(theTime()) ### ==>> func Increment = 10 if BarMan.value() >= 100 ### ProgressBar start over. BarMan.setvalue(0) ok (continues on next page) 45.32. Using QProgressBar and Timer 396
436.
Ring Documentation, Release1.16 (continued from previous page) BarMan{ setvalue(value() + Increment) } Func theTime return "Time : " + Time() 45.33 Display Scaled Image using QLabel In this example we will learn about displaying and scaling an image so that it looks “animated” using the QLabel widget Load "guilib.ring" #---------------------------------------------------- # REQUIRES: image = "C:RINGbinstock.jpg" # imageStock: start dimensions for growing image imageW = 200 ; imageH = 200 ; GrowBy = 4 ###---------------------------------------------------- ### Window and Box Size dimensions WinWidth = 1280 ; WinHeight = 960 BoxWidth = WinWidth -80 ; BoxHeight = WinHeight -80 ###---------------------------------------------------- New qapp { win1 = new qwidget() { setgeometry(50,50, WinWidth,WinHeight) setwindowtitle("Animated Image - Display Image Scaled and Resized") imageStock = new qlabel(win1) { image = new qpixmap("C:RINGbinstock.jpg") AspectRatio = image.width() / image.height() imageW = 200 imageH = imageH / AspectRatio ### Size-H, Size-V, Aspect, Transform setpixmap(image.scaled(imageW , imageH ,0,0)) (continues on next page) 45.33. Display Scaled Image using QLabel 397
437.
Ring Documentation, Release1.16 (continued from previous page) PosLeft = (BoxWidth - imageW ) / 2 PosTop = (BoxHeight - imageH ) / 2 setGeometry(PosLeft,PosTop,imageW,imageH) } TimerMan = new qtimer(win1) { setinterval(100) ### interval 100 millisecs. settimeoutevent("pTime()") ### ==>> func start() } show() } exec() } ###------------------------------------------------------ ### Function TimerMan: calling interval 100 milliseconds func pTime ### Stop Timer when image is size of Window area if imageW > BoxWidth TimerMan.stop() imageStock.clear() ### Will clear the image ok ### Grow image imageW += GrowBy imageH = imageW / AspectRatio ### Scaled Image: Size-H, Size-V, Aspect, Transform imageStock.setpixmap(image.scaled(imageW , imageH ,0,0)) ### Center the image PosLeft = (WinWidth - imageW ) / 2 PosTop = (WinHeight - imageH ) / 2 imageStock.setGeometry(PosLeft,PosTop,imageW,imageH) 45.34 Using the QFileDialog Class Example Load "guilib.ring" New qapp { win1 = new qwidget() { setwindowtitle("open file") setgeometry(100,100,400,400) new qpushbutton(win1) { setgeometry(10,10,200,30) (continues on next page) 45.34. Using the QFileDialog Class 398
438.
Ring Documentation, Release1.16 (continued from previous page) settext("open file") setclickevent("pOpen()") } show() } exec() } Func pOpen new qfiledialog(win1) { cName = getopenfilename(win1,"open file","c:","source files(*.ring)") win1.setwindowtitle(cName) } The application during the runtime 45.35 Drawing using QPainter In this example we will learn about drawing using the QPainter class Load "guilib.ring" New qapp { win1 = new qwidget() { setwindowtitle("Drawing using QPainter") setgeometry(100,100,500,500) label1 = new qlabel(win1) { setgeometry(10,10,400,400) settext("") } new qpushbutton(win1) { (continues on next page) 45.35. Drawing using QPainter 399
439.
Ring Documentation, Release1.16 (continued from previous page) setgeometry(200,400,100,30) settext("draw") setclickevent("draw()") } show() } exec() } Func draw p1 = new qpicture() color = new qcolor() { setrgb(0,0,255,255) } pen = new qpen() { setcolor(color) setwidth(10) } new qpainter() { begin(p1) setpen(pen) drawline(500,150,950,450) drawline(950,550,500,150) endpaint() } label1 { setpicture(p1) show() } The application during the runtime 45.35. Drawing using QPainter 400
440.
Ring Documentation, Release1.16 45.36 Printing using QPrinter In this example we will learn how to print to PDF file using QPrinter Load "guilib.ring" new qApp { win1 = new qwidget() { setwindowtitle("Printer") setgeometry(100,100,500,500) myweb = new qwebview(win1) { setgeometry(100,100,1000,500) loadpage(new qurl("http://google.com")) } new qpushbutton(win1) { setGeometry(20,20,100,30) settext("Print") setclickevent("print()") } (continues on next page) 45.36. Printing using QPrinter 401
441.
Ring Documentation, Release1.16 (continued from previous page) showmaximized() } exec() } func print printer1 = new qPrinter(0) { setoutputformat(1) # 1 = pdf setoutputfilename("test.pdf") painter = new qpainter() { begin(printer1) myfont = new qfont("Times",50,-1,0) setfont(myfont) drawtext(100,100,"test") printer1.newpage() drawtext(100,100,"test2") endpaint() } } printer1 = new qPrinter(0) { setoutputformat(1) setoutputfilename("test2.pdf") myweb.print(printer1,' system("test2.pdf") ') myweb.show() } system ("test.pdf") 45.37 Using QPrintPreviewDialog In this example we will learn how to use the QPrintPreviewDialog class. Example: load "guilib.ring" new qApp { win1 = new qwidget() { setwindowtitle("Printer Preview Dialog") setgeometry(100,100,800,880) printer1 = new qPrinter(0) show() oPreview = new qPrintPreviewDialog(printer1) { setParent(win1) move(10,10) setPaintrequestedevent("printPreview()") exec() } } exec() } func printPreview (continues on next page) 45.37. Using QPrintPreviewDialog 402
442.
Ring Documentation, Release1.16 (continued from previous page) printer1 { painter = new qpainter() { begin(printer1) myfont = new qfont("Times",50,-1,0) setfont(myfont) drawtext(100,100,"Test - Page (1)") printer1.newpage() drawtext(100,100,"Test - Page (2)") printer1.newpage() myfont2 = new qfont("Times",14,-1,0) setfont(myfont2) for x = 1 to 30 drawtext(100,100+(20*x),"Number : " + x) next endpaint() } } Screen Shot: 45.37. Using QPrintPreviewDialog 403
Ring Documentation, Release1.16 45.38 Creating More than one Window The next example demonstrates how to create more than one window Load "guilib.ring" app1 = new qapp { win1 = new qwidget() { setwindowtitle("First") setgeometry(100,100,500,500) new qpushbutton(win1) { setgeometry(100,100,100,30) settext("close") setclickevent("app1.quit()") } new qpushbutton(win1) { setgeometry(250,100,100,30) settext("Second") setclickevent("second()") } showmaximized() } exec() } func second win2 = new qwidget() { setwindowtitle("Second") setgeometry(100,100,500,500) setwindowflags(Qt_dialog) show() } The application during the runtime 45.38. Creating More than one Window 405
445.
Ring Documentation, Release1.16 45.39 Playing Sound Example: Load "guilib.ring" new qapp { win1 = new qwidget() { setwindowtitle("play sound!") show() } new qmediaplayer() { setmedia(new qurl("footstep.wav")) setvolume(50) play() } exec() } 45.40 Using the QColorDialog Class Example: Load "guilib.ring" oApp = new myapp { start() } Class MyApp oColor win1 Func start (continues on next page) 45.39. Playing Sound 406
446.
Ring Documentation, Release1.16 (continued from previous page) myapp = new qapp win1 = new qMainWindow() { setwindowtitle("Color Dialog") setgeometry(100,100,400,400) } new qpushbutton(win1) { setgeometry(10,10,100,30) settext("Get Color") setclickevent("oApp.pColor()") } win1.show() myapp.exec() Func pColor myobj = new qcolordialog() aColor = myobj.GetColor() r=acolor[1] g=acolor[2] b=acolor[3] win1.setstylesheet("background-color: rgb("+r+", " + g+ "," + b + ")") The application during the runtime 45.40. Using the QColorDialog Class 407
447.
Ring Documentation, Release1.16 45.41 Using qLCDNumber Class In this example we will learn about using the qLCDNumber class Load "guilib.ring" New qApp { win1 = new qWidget() { setwindowtitle("LCD Number") setgeometry(100,100,250,120) new qLCDNumber(win1) { setgeometry(10,10,100,40) display(100) } new qLCDNumber(win1) { setgeometry(10,60,100,40) display(80) } show() } exec() } The application during the runtime 45.41. Using qLCDNumber Class 408
448.
Ring Documentation, Release1.16 45.42 Movable Label Example Load "guilib.ring" new qApp { win1 = new qWidget() { label1 = new qLabel(win1) { setText("Welcome") setgeometry(10,10,200,50) setstylesheet("color: purple ; font-size: 30pt;") } new qTimer(win1) { setInterVal(10) setTimeOutEvent("pMove()") start() } setWindowTitle("Movable Label") setgeometry(100,100,600,80) setStyleSheet("background-color: white;") show() } exec() } Func pMove label1 { move(x()+1,y()) if x() > 600 move(10,y()) ok } The application during the runtime 45.42. Movable Label Example 409
449.
Ring Documentation, Release1.16 45.43 QMessagebox Example In this section we will learn how to check the output of the Message box Load "guilib.ring" new qApp { win1 = new qWidget() { label1 = new qpushbutton(win1) { setText("Test") setgeometry(10,10,200,50) setstylesheet("color: purple ; font-size: 30pt;") setclickevent("pWork()") } setWindowTitle("Messagebox") setgeometry(100,100,600,80) setStyleSheet("background-color: white;") show() } exec() } func pWork new qmessagebox(win1) { setwindowtitle("messagebox title") settext("messagebox text") setInformativeText("Do you want to save your changes?") setstandardbuttons(QMessageBox_Yes | QMessageBox_No | QMessageBox_ ˓ →Close) result = exec() win1 { if result = QMessageBox_Yes setwindowtitle("Yes") but result = QMessageBox_No setwindowtitle("No") but result = QMessageBox_Close setwindowtitle("Close") ok } } The application during the runtime 45.43. QMessagebox Example 410
450.
Ring Documentation, Release1.16 45.44 Using QInputDialog Class In the next example we will learn about using the QInputDialog class Load "guilib.ring" New QApp { Win1 = New QWidget () { SetGeometry(100,100,400,400) SetWindowTitle("Input Dialog") New QPushButton(win1) { SetText ("Input Dialog") SetGeometry(100,100,100,30) SetClickEvent("pWork()") } Show() } exec() } Func pWork oInput = New QInputDialog(win1) { setwindowtitle("What is your name?") setgeometry(100,100,400,50) setlabeltext("User Name") settextvalue("Mahmoud") (continues on next page) 45.44. Using QInputDialog Class 411
451.
Ring Documentation, Release1.16 (continued from previous page) lcheck = exec() if lCheck win1.setwindowtitle(oInput.textvalue()) ok } The application during the runtime 45.45 Dialog Functions We have the next functions SetDialogIcon(cIconFile) MsgInfo(cTitle,cMessage) ConfirmMsg(cTitle,cMessage) --> lResult InputBox(cTitle,cMessage) --> cValue InputBoxInt(cTitle,cMessage) --> nValue InputBoxNum(cTitle,cMessage) --> nValue InputBoxPass(cTitle,cMessage) --> cValue Example load "guilib.ring" new qApp { (continues on next page) 45.45. Dialog Functions 412
452.
Ring Documentation, Release1.16 (continued from previous page) SetDialogIcon("notepad.png") msginfo(:Ring,:Welcome) see confirmMsg(:Ring,"Are you sure?") + nl see InputBoxNum(:Ring,"Enter Number(double) :") + nl see InputBox(:Ring,"Enter Value :") + nl see InputBoxInt(:Ring,"Enter Number(int)") + nl see InputBoxPass(:Ring,"Enter Password") +nl } 45.46 KeyPress and Mouse Move Events In this example we will learn how to use the Events Filter to know about KeyPress and Mouse Move Events Load "guilib.ring" new qApp { win1 = new qWidget() { setWindowTitle("Test using Event Filter!") setGeometry(100,100,400,400) setmousetracking(true) myfilter = new qallevents(win1) myfilter.setKeyPressEvent("pWork()") myfilter.setMouseButtonPressevent("pClick()") myfilter.setmousemoveevent("pMove()") installeventfilter(myfilter) show() } exec() } func pWork win1.setwindowtitle('KeyPress! : ' + myfilter.getkeycode()) func pClick new qmessagebox(win1) { setgeometry(100,100,400,100) setwindowtitle("click event!") settext("x : " + myfilter.getx() + " y : " + myfilter.gety() + " button : " + myfilter.getbutton() ) show() } func pMove win1.setwindowtitle("Mouse Move , X : " + myfilter.getx() + " Y : " + myfilter.gety() ) The application during the runtime 45.46. KeyPress and Mouse Move Events 413
453.
Ring Documentation, Release1.16 45.47 Moving Objects using the Mouse In the next example we will learn how to program movable objects where the user can move a label Load "guilib.ring" lPress = false nX = 0 nY = 0 new qApp { win1 = new qWidget() { setWindowTitle("Move this label!") setGeometry(100,100,400,400) setstylesheet("background-color:white;") Label1 = new qLabel(Win1){ setGeometry(100,100,200,50) setText("Welcome") setstylesheet("font-size: 30pt") myfilter = new qallevents(label1) myfilter.setEnterevent("pEnter()") (continues on next page) 45.47. Moving Objects using the Mouse 414
454.
Ring Documentation, Release1.16 (continued from previous page) myfilter.setLeaveevent("pLeave()") myfilter.setMouseButtonPressEvent("pPress()") myfilter.setMouseButtonReleaseEvent("pRelease()") myfilter.setMouseMoveEvent("pMove()") installeventfilter(myfilter) } show() } exec() } Func pEnter Label1.setStyleSheet("background-color: purple; color:white;font-size: 30pt;") Func pLeave Label1.setStyleSheet("background-color: white; color:black;font-size: 30pt;") Func pPress lPress = True nX = myfilter.getglobalx() ny = myfilter.getglobaly() Func pRelease lPress = False pEnter() Func pMove nX2 = myfilter.getglobalx() ny2 = myfilter.getglobaly() ndiffx = nX2 - nX ndiffy = nY2 - nY if lPress Label1 { move(x()+ndiffx,y()+ndiffy) setStyleSheet("background-color: Green; color:white;font-size: 30pt;") nX = nX2 ny = nY2 } ok The application during the runtime 45.47. Moving Objects using the Mouse 415
Ring Documentation, Release1.16 45.48 Inheritance from GUI Classes Example : Load "guilib.ring" New MyWindow() new qApp { exec() } class mywindow from qwidget Func init super.init() setwindowtitle("First Window") setgeometry(100,100,400,400) setstylesheet("background-color: purple;") settooltip("my first window!") show() The application during the runtime 45.48. Inheritance from GUI Classes 418
458.
Ring Documentation, Release1.16 45.49 Using QDesktopWidget Class In the next example we will learn about using the QDesktopWidget class Load "guilib.ring" New qApp { win1 = New qWidget() { resize(400,400) btn1 = new qPushbutton(win1) { setText("Center") move(100,100) resize(100,30) setClickEvent("pCenter()") } Show() } exec() } Func pCenter (continues on next page) 45.49. Using QDesktopWidget Class 419
459.
Ring Documentation, Release1.16 (continued from previous page) oDesktop = new qDesktopWidget() oRect = oDesktop.screenGeometry( oDesktop.primaryScreen() ) win1.move((oRect.width()-win1.width()) /2 , (oRect.Height()-win1.Height())/2 ) win1.show() The application during the runtime 45.50 Rotate Text The next example rotate text using a Timer. Load "guilib.ring" nAngle = 0 New qapp { win1 = new qwidget() { setwindowtitle("Rotate Text") resize(800,600) label1 = new qlabel(win1) { settext("") myfilter = new qallevents(win1) myfilter.setMouseButtonPressevent("pClick()") installeventfilter(myfilter) (continues on next page) 45.50. Rotate Text 420
460.
Ring Documentation, Release1.16 (continued from previous page) } new qtimer(win1) { setinterval(50) settimeoutevent("pTime()") start() } pDraw() L1 = new qVBoxLayout() { AddWidget(Label1) } SetLayout(L1) showMaximized() } exec() } Func pDraw p1 = new qpicture() color = new qcolor() { setrgb(0,0,255,255) } pen = new qpen() { setcolor(color) setwidth(50) } painter = new qpainter() { begin(p1) setpen(pen) myfont = font() myfont.setpointsize(50) setfont(myfont) rotate(nAngle) drawtext(350,0*nAngle,"welcome") drawtext(0,0*nAngle,"welcome") endpaint() } label1 { setpicture(p1) show() } Func pClick win1 { setwindowtitle("Click Event") } Func pTime nAngle++ if nAngle = 90 nAngle = 10 ok pDraw() The application during the runtime 45.50. Rotate Text 421
461.
Ring Documentation, Release1.16 45.51 Change Focus The next example change the focus using the ENTER key. load "guilib.ring" new qApp { win = new qWidget() { resize(600,600) SetWindowTitle("Change Focus") text1 = new qLineEdit(win) text2 = new qLineEdit(win) text3 = new qLineEdit(win) text4 = new qLineEdit(win) layout1 = new qVBoxLayout() { AddWidget(text1) AddWidget(text2) AddWidget(text3) AddWidget(text4) } (continues on next page) 45.51. Change Focus 422
462.
Ring Documentation, Release1.16 (continued from previous page) setLayout(Layout1) aList = [text1,text2,text3,text4] oFilter = new qallevents(win) oFilter.setKeyPressEvent("pWork()") installeventfilter(oFilter) show() } exec() } func pWork nCode = oFilter.getkeycode() if nCode = 16777220 # ENTER Key for x=1 to len(aList) if aList[x].HasFocus() t = x+1 if t > len(aList) t=1 ok aList[t].SetFocus(0) exit ok next ok 45.52 Regular Expressions The next example uses the Regular Expressions classes. load "guilib.ring" new qApp { see "Using Regular Expressions" + nl exp = new qregularexpression() { setPattern("dd w+") see pattern() + nl match = match("33 one",0,0,0) see match.hasmatch() + nl match = match("3 one",0,0,0) see match.hasmatch() + nl match = match("welcome 11 one",0,0,0) see match.hasmatch() + nl matched = match.captured(0) see matched + nl } exp = new qregularexpression() { setPattern("^(dd)/(dd)/(dddd)$") see pattern() + nl match = match("08/12/1985",0,0,0) see match.hasmatch() + nl day = match.captured(1) month = match.captured(2) year = match.captured(3) see day + nl + month + nl + year + nl (continues on next page) 45.52. Regular Expressions 423
463.
Ring Documentation, Release1.16 (continued from previous page) see "(" + match.capturedStart(1) + "," + match.capturedEnd(1)+ ")" + ˓ →nl see "(" + match.capturedStart(2) + "," + match.capturedEnd(2)+ ")" + ˓ →nl see "(" + match.capturedStart(3) + "," + match.capturedEnd(3)+ ")" + ˓ →nl } } Output Using Regular Expressions dd w+ 1 0 1 11 one ^(dd)/(dd)/(dddd)$ 1 08 12 1985 (0,2) (3,5) (6,10) 45.53 Simple Client and Server Example In this section we will learn about creating simple Client and Server Application Load "guilib.ring" new qApp { oClient = new Client { client() } oServer = new Server { server() } exec() } Class Client win1 lineedit1 cOutput="" oTcpSocket func client win1 = new qwidget() new qpushbutton(win1) { setgeometry(50,50,100,30) settext("connect") setclickevent("oClient.Connect()") } (continues on next page) 45.53. Simple Client and Server Example 424
464.
Ring Documentation, Release1.16 (continued from previous page) lineedit1 = new qtextedit(win1) { setGeometry(150,50,200,300) } win1 { setwindowtitle("client") setgeometry(10,100,400,400) show() } func connect cOutput = "Connect to host 127.0.0.1 port 9999" + nl lineedit1.settext(cOutput) oTcpSocket = new qTcpSocket(win1) { setconnectedevent("oClient.pConnected()") setreadyreadevent("oClient.pRead()") connecttohost("127.0.0.1",9999,3,0) waitforconnected(5000) } func pConnected cOutput += "Connected!" + nl lineedit1.settext(cOutput) func pRead cOutput += "Ready Read!" + nl lineedit1.settext(cOutput) cOutput += oTcpSocket.readall().data() + nl lineedit1.settext(cOutput) Class Server win1 lineedit1 oTcpServer oTcpClient cOutput = "" func server win1 = new qwidget() lineedit1 = new qtextedit(win1) { setGeometry(150,50,200,300) } win1 { setwindowtitle("Server") setgeometry(450,100,400,400) show() } oTcpServer = new qTcpServer(win1) { setNewConnectionEvent("oServer.pNewConnection()") oHostAddress = new qHostAddress() oHostAddress.SetAddress("127.0.0.1") listen(oHostAddress,9999) (continues on next page) 45.53. Simple Client and Server Example 425
465.
Ring Documentation, Release1.16 (continued from previous page) } cOutput = "Server Started" + nl + "listen to port 9999" + nl lineedit1.settext(cOutput) Func pNewConnection oTcpClient = oTcpServer.nextPendingConnection() cOutput += "Accept Connection" + nl lineedit1.settext(cOutput) oTcpClient { cStr ="Hello from server to client!"+char(13)+char(10) write(cStr,len(cStr)) flush() waitforbyteswritten(300000) close() } The application during the runtime 45.54 Dynamic Objects We may create objects in the runtime and add them to windows. Example: load "guilib.ring" oFormDesigner = new FormDesigner { start("oFormDesigner") } (continues on next page) 45.54. Dynamic Objects 426
466.
Ring Documentation, Release1.16 (continued from previous page) Class FormDesigner winToolBox winForm aObjects = [] func start cObjectName oApp = new qApp winToolBox = new qWidget() winToolBox.setWindowTitle("ToolBox") winToolBox.move(10,10) winToolBox.resize(300,600) btn = new qPushButton(winToolBox) btn.resize(300,30) btn.setText("Create Button") btn.setClickEvent(cObjectName+".pCreateButton()") btn.show() winToolBox.show() winForm = new qWidget() { move(400,50) setWindowTitle("Form Designer") resize(600,600) show() } oApp.exec() func pCreateButton nCount = len(aObjects) aObjects + new MyButton(winForm) { nIndex = nCount + 1 setText("Button"+ nIndex) Move(30*nIndex,30*nIndex) resize(100,30) show() } Class MyButton from qPushButton nIndex = 0 45.54. Dynamic Objects 427
467.
Ring Documentation, Release1.16 45.55 Weight History Application The next sample help in recording (Date, Time and Weight). Load "guilib.ring" MyApp = new qApp { $ApplicationObject = "oApp" # To be used when calling events oApp = new App exec() oApp.CloseDatabase() } class App cDir = currentdir() + "/" oCon aIDs = [] win1 = new qWidget() { setWindowTitle("Weight History") resize(600,600) layoutButtons = new qhboxlayout() { label1 = new qLabel(win1) { setText("Weight") } text1 = new qlineedit(win1) btnAdd = new qpushbutton(win1) { setText("Add") setClickEvent($ApplicationObject+".AddWeight()") } btnDelete = new qpushbutton(win1) { setText("Delete") setClickEvent($ApplicationObject+".Deleteweight()") } addwidget(label1) addwidget(text1) addwidget(btnAdd) addwidget(btnDelete) } layoutData = new qhboxlayout() { Table1 = new qTableWidget(win1) { setrowcount(0) setcolumncount(3) setselectionbehavior(QAbstractItemView_SelectRows) setHorizontalHeaderItem(0, new QTableWidgetItem("Date")) setHorizontalHeaderItem(1, new QTableWidgetItem("Time")) setHorizontalHeaderItem(2, new QTableWidgetItem("Weight")) setitemChangedEvent($ApplicationObject+".ItemChanged()") setAlternatingRowColors(true) horizontalHeader().setStyleSheet("color: blue") verticalHeader().setStyleSheet("color: red") } addWidget(Table1) } (continues on next page) 45.55. Weight History Application 428
468.
Ring Documentation, Release1.16 (continued from previous page) layoutClose = new qhboxlayout() { btnclose = new qpushbutton(win1) { setText("Close") setClickEvent("MyApp.Quit()") } addwidget(btnClose) } layoutMain = new qvboxlayout() { addlayout(layoutButtons) addLayout(LayoutData) addLayout(layoutClose) } setlayout(layoutMain) self.OpenDatabase() self.ShowRecords() show() } Func OpenDatabase lCreate = False if not fexists(cDir + "weighthistory.db") lCreate = True ok new QSqlDatabase() { this.oCon = addDatabase("QSQLITE") { setDatabaseName("weighthistory.db") Open() } } if lCreate new QSqlQuery( ) { exec("create table weighthistory (id integer primary key,"+ " f_date varchar(10),"+ " f_time varchar(8), f_weight varchar(8) );") delete() } ok Func CloseDatabase oCon.Close() Func AddWeight cWeight = text1.text() AddRecord(cWeight) Func DeleteWeight Table1 { nRow = CurrentRow() if nRow >= 0 nID = this.aIDs[nROW+1] new QSqlQuery( ) { exec("delete from weighthistory where id = " + nID ) } Del(this.aIDs,nRow+1) (continues on next page) 45.55. Weight History Application 429
469.
Ring Documentation, Release1.16 (continued from previous page) removerow(nRow) selectrow(nRow) ok } Func AddRecord cWeight new QSqlQuery( ) { cStr = "insert into weighthistory (f_date,f_time,f_weight) values"+ " ('%f1','%f2','%f3')" cDate = Date() cTime = Time() cStr = substr(cStr,"%f1",cDate) cStr = substr(cStr,"%f2",cTime) cStr = substr(cStr,"%f3",cWeight) exec(cStr) delete() } ShowRecords() Table1.selectrow(table1.rowcount()-1) Func ShowRecords table1.setitemChangedEvent("") aIDs = [] query = new QSqlQuery() { exec("select * from weighthistory") nRows = 0 this.Table1.setrowcount(0) while movenext() this.table1 { insertRow(nRows) this.aIDs + query.value(0).tostring() for x = 1 to 3 cStr = query.value(x).tostring() item = new qTableWidgetItem(cStr) setItem(nRows,x-1,item) next } nRows++ end delete() } table1.setitemChangedEvent($ApplicationObject+".ItemChanged()") Func ItemChanged nRow = table1.currentrow() if nRow >= 0 myitem = Table1.item(table1.currentrow(),0) cDate = myitem.text() myitem = Table1.item(table1.currentrow(),1) cTime = myitem.text() myitem = Table1.item(table1.currentrow(),2) cWeight = myitem.text() new QSqlQuery( ) { cStr = "update weighthistory set f_date ='%f1' , f_time = '%f2' , "+ "f_weight ='%f3' where id = " + this.aIDs[nROW+1] (continues on next page) 45.55. Weight History Application 430
470.
Ring Documentation, Release1.16 (continued from previous page) cStr = substr(cStr,"%f1",cDate) cStr = substr(cStr,"%f2",cTime) cStr = substr(cStr,"%f3",cWeight) exec(cStr) delete() } ok The next screen shot for the application during the runtime 45.55. Weight History Application 431
471.
Ring Documentation, Release1.16 45.56 Notepad Application In the next example we will see simple Notepad developed using the RingQt Load "guilib.ring" cActiveFileName = "" aTextColor = [0,0,0] aBackColor = [255,255,255] cFont = "MS Shell Dlg 2,14,-1,5,50,0,0,0,0,0" cWebsite = "http://www.google.com" oSearch = NULL oSearchValue = NULL oSearchCase = NULL oSearchFilter = NULL oReplaceValue = NULL lAskToSave = false MyApp = New qApp { win1 = new qMainWindow() { setwindowtitle("Ring Notepad") setGeometry(100,100,400,400) aBtns = [ new qpushbutton(win1) { setbtnimage(self,"image/new.png") setclickevent("pNew()") settooltip("New File") } , new qpushbutton(win1) { setbtnimage(self,"image/open.png") setclickevent("pOpen()") settooltip("Open File") } , new qpushbutton(win1) { setbtnimage(self,"image/save.png") setclickevent("pSave()") settooltip("Save") } , new qpushbutton(win1) { setbtnimage(self,"image/saveas.png") setclickevent("pSaveAs()") settooltip("Save As") } , new qpushbutton(win1) { setbtnimage(self,"image/cut.png") setclickevent("pCut()") settooltip("Cut") } , new qpushbutton(win1) { setbtnimage(self,"image/copy.png") setclickevent("pCopy()") settooltip("Copy") } , new qpushbutton(win1) { (continues on next page) 45.56. Notepad Application 432
472.
Ring Documentation, Release1.16 (continued from previous page) setbtnimage(self,"image/paste.png") setclickevent("pPaste()") settooltip("Paste") } , new qpushbutton(win1) { setbtnimage(self,"image/font.png") setclickevent("pFont()") settooltip("Font") } , new qpushbutton(win1) { setbtnimage(self,"image/colors.jpg") setclickevent("pColor()") settooltip("Text Color") } , new qpushbutton(win1) { setbtnimage(self,"image/search.png") setclickevent("pFind()") settooltip("Find and Replace") } , new qpushbutton(win1) { setbtnimage(self,"image/print.png") setclickevent("pPrint()") settooltip("Print") } , new qpushbutton(win1) { setbtnimage(self,"image/debug.png") setclickevent("pDebug()") settooltip("Debug (Run then wait!)") } , new qpushbutton(win1) { setbtnimage(self,"image/run.png") setclickevent("pRun()") settooltip("Run the program") } , new qpushbutton(win1) { setbtnimage(self,"image/close.png") setclickevent("pQuit()") settooltip("Quit") } ] tool1 = addtoolbar("files") { for x in aBtns addwidget(x) addseparator() next } menu1 = new qmenubar(win1) { sub1 = addmenu("File") sub2 = addmenu("Edit") sub3 = addmenu("View") sub4 = addmenu("Help") sub1 { oAction = new qAction(win1) { setShortcut(new QKeySequence("Ctrl+n")) setbtnimage(self,"image/new.png") settext("New") setclickevent("pNew()") } (continues on next page) 45.56. Notepad Application 433
473.
Ring Documentation, Release1.16 (continued from previous page) addaction(oAction) oAction = new qAction(win1) { setShortcut(new QKeySequence("Ctrl+o")) setbtnimage(self,"image/open.png") settext("Open") setclickevent("pOpen()") } addaction(oAction) addseparator() oAction = new qAction(win1) { setShortcut(new QKeySequence("Ctrl+s")) setbtnimage(self,"image/save.png") settext("Save") setclickevent("pSave()") } addaction(oAction) addseparator() oAction = new qAction(win1) { setShortcut(new QKeySequence("Ctrl+e")) setbtnimage(self,"image/saveas.png") settext("Save As") setclickevent("pSaveAs()") } addaction(oAction) addseparator() oAction = new qAction(win1) { setShortcut(new QKeySequence("Ctrl+p")) setbtnimage(self,"image/print.png") settext("Print to PDF") setclickevent("pPrint()") } addaction(oAction) addseparator() oAction = new qAction(win1) { setShortcut(new QKeySequence("Ctrl+d")) setbtnimage(self,"image/debug.png") settext("Debug (Run then wait!)") setclickevent("pDebug()") } addaction(oAction) addseparator() oAction = new qAction(win1) { setShortcut(new QKeySequence("Ctrl+r")) setbtnimage(self,"image/run.png") settext("Run") setclickevent("pRun()") } addaction(oAction) addseparator() oAction = new qAction(win1) { setShortcut(new QKeySequence("Ctrl+F5")) setbtnimage(self,"image/run.png") settext("Run GUI Application (No Console)") setclickevent("pRunNoConsole()") } addaction(oAction) addseparator() (continues on next page) 45.56. Notepad Application 434
474.
Ring Documentation, Release1.16 (continued from previous page) oAction = new qaction(win1) { setShortcut(new QKeySequence("Ctrl+q")) setbtnimage(self,"image/close.png") settext("Exit") setstatustip("Exit") setclickevent("pQuit()") } addaction(oAction) } sub2 { oAction = new qAction(win1) { setShortcut(new QKeySequence("Ctrl+x")) setbtnimage(self,"image/cut.png") settext("Cut") setclickevent("pCut()") } addaction(oAction) oAction = new qAction(win1) { setShortcut(new QKeySequence("Ctrl+c")) setbtnimage(self,"image/copy.png") settext("Copy") setclickevent("pCopy()") } addaction(oAction) oAction = new qAction(win1) { setShortcut(new QKeySequence("Ctrl+v")) setbtnimage(self,"image/paste.png") settext("Paste") setclickevent("pPaste()") } addaction(oAction) addseparator() oAction = new qAction(win1) { setShortcut(new QKeySequence("Ctrl+i")) setbtnimage(self,"image/font.png") settext("Font") setclickevent("pFont()") } addseparator() addaction(oAction) oAction = new qAction(win1) { setShortcut(new QKeySequence("Ctrl+t")) setbtnimage(self,"image/colors.jpg") settext("Text Color") setclickevent("pColor()") } addaction(oAction) oAction = new qAction(win1) { setShortcut(new QKeySequence("Ctrl+b")) setbtnimage(self,"image/colors.jpg") settext("Back Color") setclickevent("pColor2()") } addaction(oAction) addseparator() oAction = new qAction(win1) { setShortcut(new QKeySequence("Ctrl+g")) (continues on next page) 45.56. Notepad Application 435
475.
Ring Documentation, Release1.16 (continued from previous page) settext("Go to line") setclickevent("pGoto()") } addaction(oAction) oAction = new qAction(win1) { setShortcut(new QKeySequence("Ctrl+f")) setbtnimage(self,"image/search.png") settext("Find and Replace") setclickevent("pFind()") } addaction(oAction) } sub3 { oAction = new qAction(win1) { setShortcut(new QKeySequence("Ctrl+p")) setbtnimage(self,"image/project.png") settext("Project Files") setclickevent("pProject()") } addaction(oAction) oAction = new qAction(win1) { setShortcut(new QKeySequence("Ctrl+u")) setbtnimage(self,"image/source.png") setclickevent("pSourceCode()") settext("Source Code") } addaction(oAction) oAction = new qAction(win1) { setShortcut(new QKeySequence("Ctrl+w")) setbtnimage(self,"image/richtext.png") setclickevent("pWebBrowser()") settext("Web Browser") } addaction(oAction) } sub4 { sub5 = addmenu("Development Tools") sub5 { oAction = new qAction(win1) { settext("Programming Language") setclickevent("pLang()") } addaction(oAction) oAction = new qAction(win1) { settext("GUI Library") setclickevent("pGUI()") } addaction(oAction) } addseparator() oAction = new qAction(win1) { settext("About") setclickevent("pAbout()") } addaction(oAction) } (continues on next page) 45.56. Notepad Application 436
476.
Ring Documentation, Release1.16 (continued from previous page) } setmenubar(menu1) status1 = new qstatusbar(win1) { showmessage("Ready!",0) } setstatusbar(status1) tree1 = new qtreeview(win1) { setclickedevent("pChangeFile()") setGeometry(00,00,200,400) oDir = new QDir() ofile = new QFileSystemModel() { setrootpath(oDir.currentpath()) myfiles = new qstringlist() myfiles.append("*.ring") myfiles.append("*.rh") setnamefilters(myfiles) setNameFilterDisables(false) } setmodel(ofile) myindex = ofile.index(oDir.currentpath(),0) for x = 1 to ofile.columncount() hidecolumn(x) next setcurrentindex(myindex) setexpanded(myindex,true) header().hide() } oDock1 = new qdockwidget(win1,0) { setGeometry(00,00,200,200) setwindowtitle("Project Files") setwidget(tree1) } textedit1 = new qtextedit(win1) { setCursorPositionChangedevent("pCursorPositionChanged()") setLineWrapMode(QTextEdit_NoWrap) setAcceptRichText(false) setTextChangedEvent("lAskToSave = true") } oDock2 = new qdockwidget(win1,0) { setwidget(textedit1) setwindowtitle("Source Code") } oWebBrowser = new qWidget() { setWindowFlags(Qt_SubWindow) oWBLabel = new qLabel(win1) { setText("Website: ") } oWBText = new qLineEdit(win1) { (continues on next page) 45.56. Notepad Application 437
477.
Ring Documentation, Release1.16 (continued from previous page) setText(cWebSite) setReturnPressedEvent("pWebGo()") } oWBGo = new qPushButton(win1) { setText("Go") setClickEvent("pWebGo()") } oWBBack = new qPushButton(win1) { setText("Back") setClickEvent("pWebBack()") } oWBLayout1 = new qHBoxLayout() { addWidget(oWBLabel) addWidget(oWBText) addWidget(oWBGo) addWidget(oWBBack) } oWebView = new qWebView(win1) { loadpage(new qurl(cWebSite)) } oWBlayout2 = new qVBoxLayout() { addLayout(oWBLayout1) addWidget(oWebView) } setLayout(oWBLayout2) } oDock3 = new qdockwidget(win1,0) { setwidget(oWebBrowser) setwindowtitle("Web Browser") setFeatures(QDockWidget_DocWidgetClosable) } adddockwidget(1,oDock1,1) adddockwidget(2,oDock2,2) adddockwidget(2,oDock3,1) setwinicon(self,"image/notepad.png") showmaximized() } RestoreSettings() exec() } func pWebGo cWebsite = oWBText.text() oWebView.LoadPage( new qurl( cWebSite ) ) func pWebBack oWebView.Back() func pProject oDock1.Show() func pSourceCode oDock2.Show() (continues on next page) 45.56. Notepad Application 438
478.
Ring Documentation, Release1.16 (continued from previous page) func pWebBrowser oDock3.Show() func pChangeFile myitem = tree1.currentindex() if ofile.isdir(myitem) return ok cActiveFileName = ofile.filepath(myitem) textedit1.settext(read(cActiveFileName)) textedit1.setfocus(0) pCursorPositionChanged() pSetActiveFileName() func pSetActiveFileName oDock2.setWindowTitle("Source Code : " + cActiveFileName) func pCursorPositionChanged status1.showmessage(" Line : "+(textedit1.textcursor().blocknumber()+1)+ " Column : " +(textedit1.textcursor().columnnumber()+1) + " Total Lines : " + textedit1.document().linecount() ,0) func pGoto oInput = New QInputDialog(win1) { setwindowtitle("Enter the line number?") setgeometry(100,100,400,50) setlabeltext("Line") settextvalue("1") exec() nLine = 0 + oInput.textvalue() oBlock = textedit1.document().findBlockByLineNumber(nLine-1) oCursor = textedit1.textcursor() oCursor.setposition(oBlock.position(),0) textedit1.settextcursor(oCursor) } func pFind if isobject(oSearch) oSearch.activatewindow() return ok oSearch = new qWidget() { new qLabel(oSearch) { setText("Find What : ") setgeometry(10,10,50,30) } oSearchValue = new qlineedit(oSearch) { setgeometry(80,10,460,30) setReturnPressedEvent("pFindValue()") } new qLabel(oSearch) { (continues on next page) 45.56. Notepad Application 439
479.
Ring Documentation, Release1.16 (continued from previous page) setText("Replace with ") setgeometry(10,45,80,30) } oReplaceValue = new qlineedit(oSearch) { setgeometry(80,45,460,30) } oSearchCase = new qCheckbox(oSearch) { setText("Case Sensitive") setgeometry(80,85,100,30) } new qPushButton(oSearch) { setText("Find/Find Next") setgeometry(80,120,100,30) setclickevent("pFindValue()") } new qPushButton(oSearch) { setText("Replace") setgeometry(200,120,100,30) setclickevent("pReplace()") } new qPushButton(oSearch) { setText("Replace All") setgeometry(320,120,100,30) setclickevent("pReplaceAll()") } new qPushButton(oSearch) { setText("Close") setgeometry(440,120,100,30) setclickevent("pSearchClose()") } setwinicon(oSearch,"image/notepad.png") setWindowTitle("Find/Replace") setStyleSheet("background-color:white;") setFixedsize(550,160) setwindowflags( Qt_CustomizeWindowHint | Qt_WindowTitleHint | Qt_WindowStaysOnTopHint) oSearchFilter = new qallevents(oSearch) oSearchFilter.setKeyPressEvent("pSearchKeyPress()") installeventfilter(oSearchFilter) show() } Func pReplace oCursor = textedit1.textCursor() if oCursor.HasSelection() = false new qMessagebox(oSearch) { SetWindowTitle("Replace") (continues on next page) 45.56. Notepad Application 440
480.
Ring Documentation, Release1.16 (continued from previous page) SetText("No Selection") show() } return false ok cValue = oSearchValue.text() cSelected = oCursor.SelectedText() if oSearchCase.checkState() = Qt_Unchecked cValue = lower(cValue) cSelected = lower(cSelected) ok if cSelected != cValue new qMessagebox(oSearch) { SetWindowTitle("Replace") SetText("No Match") show() } return false ok cValue = oReplaceValue.text() nStart = oCursor.SelectionStart() nEnd = oCursor.SelectionEnd() cStr = textedit1.toPlainText() cStr = left(cStr,nStart)+cValue+substr(cStr,nEnd+1) textedit1.setText(cStr) return pFindValue() Func pReplaceAll cStr = textedit1.toPlainText() cOldValue = oSearchValue.text() cNewValue = oReplaceValue.text() if oSearchCase.checkState() = Qt_Unchecked # Not Case Sensitive cStr = SubStr(cStr,cOldValue,cNewValue,true) else # Case Sensitive cStr = SubStr(cStr,cOldValue,cNewValue) ok textedit1.setText(cStr) new qMessagebox(oSearch) { SetWindowTitle("Replace All") SetText("Operation Done") show() } Func pSearchClose oSearch.close() oSearch = NULL func pSearchKeyPress if oSearchFilter.getKeyCode() = Qt_Key_Escape pSearchClose() ok func pFindValue (continues on next page) 45.56. Notepad Application 441
481.
Ring Documentation, Release1.16 (continued from previous page) oCursor = textedit1.textcursor() nPosStart = oCursor.Position() + 1 cValue = oSearchValue.text() cStr = textedit1.toplaintext() cStr = substr(cStr,nPosStart) if oSearchCase.checkState() = Qt_Unchecked cStr = lower(cStr) cValue = lower(cValue) ok nPos = substr(cStr,cValue) if nPos > 0 nPos += nPosStart - 2 oCursor = textedit1.textcursor() oCursor.setposition(nPos,0) textedit1.settextcursor(oCursor) oCursor = textedit1.textcursor() oCursor.setposition(nPos+len(cValue),1) textedit1.settextcursor(oCursor) return true else new qMessagebox(oSearch) { SetWindowTitle("Search") SetText("Cannot find :" + cValue) show() } return false ok func pNofileopened New qMessageBox(win1) { setWindowTitle("Sorry") setText("Save the file first!") show() } func pDebug if cActiveFileName = Null return pNofileopened() ok cCode = "start run " + cActiveFileName + nl system(cCode) func pRun if cActiveFileName = Null return pNofileopened() ok cCode = "start ring " + cActiveFileName + nl system(cCode) func pRunNoConsole if cActiveFileName = Null return pNofileopened() ok cCode = "start /b ring " + cActiveFileName + nl system(cCode) func pSave if cActiveFileName = NULL return pSaveAs() ok writefile(cActiveFileName,textedit1.toplaintext()) status1.showmessage("File : " + cActiveFileName + " saved!",0) lAskToSave = false func pSaveAs (continues on next page) 45.56. Notepad Application 442
Ring Documentation, Release1.16 (continued from previous page) aBackColor[1] + "," + aBackColor[2] + "," + aBackColor[3] + ")") func pOpen new qfiledialog(win1) { cName = getopenfilename(win1,"open file","c:","source files(*.ring)") if cName != NULL cActiveFileName = cName textedit1.settext(read(cActiveFileName)) ok } func pNew new qfiledialog(win1) { cName = getsavefilename(win1,"New file","","source files(*.ring)") if cName != NULL write(cName,"") cActiveFileName = cName textedit1.settext(read(cActiveFileName)) ok } Func WriteFile cFileName,cCode aCode = str2list(cCode) fp = fopen(cFileName,"wb") for cLine in aCode fwrite(fp,cLine+char(13)+char(10)) next fclose(fp) Func MsgBox cTitle,cMessage new qMessagebox(win1) { setwindowtitle(cTitle) setText(cMessage) show() } Func pLang MsgBox("Programming Language", "This application developed using the Ring programming language") Func pGUI MsgBox("GUI Library", "This application uses the Qt GUI Library through RingQt") Func pAbout MsgBox("About", "2016, Mahmoud Fayed <msfclipper@yahoo.com>") Func pSaveSettings cSettings = "aTextColor = ["+aTextColor[1]+","+aTextColor[2]+ ","+aTextColor[3]+"]" + nl + "aBackColor = ["+aBackColor[1]+","+aBackColor[2]+ ","+aBackColor[3]+"]" + nl + "cFont = '" + cFont + "'" + nl + (continues on next page) 45.56. Notepad Application 444
484.
Ring Documentation, Release1.16 (continued from previous page) "cWebSite = '" + cWebsite + "'" + nl cSettings = substr(cSettings,nl,char(13)+char(10)) write("ringnotepad.ini",cSettings) if lAsktoSave new qmessagebox(win1) { setwindowtitle("Save Changes?") settext("Some changes are not saved!") setInformativeText("Do you want to save your changes?") setstandardbuttons(QMessageBox_Yes | QMessageBox_No | QMessageBox_Cancel) result = exec() win1 { if result = QMessageBox_Yes pSave() but result = QMessageBox_Cancel return false ok } } ok return true Func pSetWebsite oWebView { loadpage(new qurl(cWebSite)) } oWBText { setText(cWebSite) } Func RestoreSettings eval(read("ringnotepad.ini")) pSetColors() pSetFont() pSetWebsite() Func pQuit if pSaveSettings() myapp.quit() ok The application during the runtime The next screen shot demonstrates the “File” menu 45.56. Notepad Application 445
485.
Ring Documentation, Release1.16 The next window for “search and replace” The next screen shot demonstrates the application main window 45.56. Notepad Application 446
486.
Ring Documentation, Release1.16 Note: the functions pDebug(), pRun() and pRunNoConsole() in the previous sample are not portable! They are written in this sample for MS-Windows and we can update them for other operating systems. 45.57 The Cards Game In the next example we will see a simple Cards game developed using RingQt Each player get 5 cards, the cards are unknown to any one. each time one player click on one card to see it. if the card is identical to another card the play get point for each card. if the card value is “5” the player get points for all visible cards. Load "guilib.ring" nScale = 1 app1 = new qApp mypic = new QPixmap("cards.jpg") mypic2 = mypic.copy(0,(124*4)+1,79,124) Player1EatPic = mypic.copy(80,(124*4)+1,79,124) Player2EatPic= mypic.copy(160,(124*4)+1,79,124) aMyCards = [] aMyValues = [] for x1 = 0 to 3 for y1 = 0 to 12 temppic = mypic.copy((79*y1)+1,(124*x1)+1,79,124) aMyCards + temppic aMyValues + (y1+1) (continues on next page) 45.57. The Cards Game 447
487.
Ring Documentation, Release1.16 (continued from previous page) next next nPlayer1Score = 0 nPlayer2Score=0 do Page1 = new Game Page1.Start() again Page1.lnewgame mypic.delete() mypic2.delete() Player1EatPic.delete() Player2EatPic.delete() for t in aMyCards t.delete() next func gui_setbtnpixmap pBtn,pPixmap pBtn { setIcon(new qicon(pPixmap.scaled(width(),height(),0,0))) setIconSize(new QSize(width(),height())) } Class Game nCardsCount = 10 win1 layout1 label1 label2 layout2 layout3 aBtns aBtns2 aCards nRole=1 aStatus = list(nCardsCount) aStatus2 = aStatus aValues aStatusValues = aStatus aStatusValues2 = aStatus Player1EatPic Player2EatPic lnewgame = false nDelayEat = 0.5 nDelayNewGame = 1 func start win1 = new qWidget() { setwindowtitle("Five") setstylesheet("background-color: White") showfullscreen() } layout1 = new qvboxlayout() label1 = new qlabel(win1) { settext("Player (1) - Score : " + nPlayer1Score) setalignment(Qt_AlignHCenter | Qt_AlignVCenter) setstylesheet("color: White; background-color: Purple; font-size:20pt") setfixedheight(200) } closebtn = new qpushbutton(win1) { settext("Close Application") setstylesheet("font-size: 18px ; color : white ; (continues on next page) 45.57. The Cards Game 448
488.
Ring Documentation, Release1.16 (continued from previous page) background-color: black ;") setclickevent("Page1.win1.close()") } aCards = aMyCards aValues = aMyValues layout2 = new qhboxlayout() aBtns = [] for x = 1 to nCardsCount aBtns + new qpushbutton(win1) aBtns[x].setfixedwidth(79*nScale) aBtns[x].setfixedheight(124*nScale) gui_setbtnpixmap(aBtns[x],mypic2) layout2.addwidget(aBtns[x]) aBtns[x].setclickevent("Page1.Player1click("+x+")") next layout1.addwidget(label1) layout1.addlayout(layout2) label2 = new qlabel(win1) { settext("Player (2) - Score : " + nPlayer2Score) setalignment(Qt_AlignHCenter | Qt_AlignVCenter) setstylesheet("color: white; background-color: red; font-size:20pt") setfixedheight(200) } layout3 = new qhboxlayout() aBtns2 = [] for x = 1 to nCardsCount aBtns2 + new qpushbutton(win1) aBtns2[x].setfixedwidth(79*nScale) aBtns2[x].setfixedheight(124*nScale) gui_setbtnpixmap(aBtns2[x],mypic2) layout3.addwidget(aBtns2[x]) aBtns2[x].setclickevent("Page1.Player2click("+x+")") next layout1.addwidget(label2) layout1.addlayout(layout3) layout1.addwidget(closebtn) win1.setlayout(layout1) app1.exec() Func Player1Click x if nRole = 1 and aStatus[x] = 0 nPos = ((random(100)+clock())%(len(aCards)-1)) + 1 gui_setbtnpixmap(aBtns[x],aCards[nPos]) del(aCards,nPos) nRole = 2 (continues on next page) 45.57. The Cards Game 449
489.
Ring Documentation, Release1.16 (continued from previous page) aStatus[x] = 1 aStatusValues[x] = aValues[nPos] del(aValues,nPos) Player1Eat(x,aStatusValues[x]) checknewgame() ok Func Player2Click x if nRole = 2 and aStatus2[x] = 0 nPos = ((random(100)+clock())%(len(aCards)-1)) + 1 gui_setbtnpixmap(aBtns2[x],aCards[nPos]) del(aCards,nPos) nRole = 1 aStatus2[x] = 1 aStatusValues2[x] = aValues[nPos] del(aValues,nPos) Player2Eat(x,aStatusValues2[x]) checknewgame() ok Func Player1Eat nPos,nValue app1.processEvents() delay(nDelayEat) lEat = false for x = 1 to nCardsCount if aStatus2[x] = 1 and (aStatusValues2[x] = nValue or ˓ →nValue=5) aStatus2[x] = 2 gui_setbtnpixmap(aBtns2[x],Player1EatPic) lEat = True nPlayer1Score++ ok if (x != nPos) and (aStatus[x] = 1) and (aStatusValues[x] = nValue or nValue=5) aStatus[x] = 2 gui_setbtnpixmap(aBtns[x],Player1EatPic) lEat = True nPlayer1Score++ ok next if lEat nPlayer1Score++ gui_setbtnpixmap(aBtns[nPos],Player1EatPic) aStatus[nPos] = 2 label1.settext("Player (1) - Score : " + ˓ →nPlayer1Score) ok Func Player2Eat nPos,nValue app1.processEvents() delay(nDelayEat) lEat = false for x = 1 to nCardsCount (continues on next page) 45.57. The Cards Game 450
490.
Ring Documentation, Release1.16 (continued from previous page) if aStatus[x] = 1 and (aStatusValues[x] = nValue or nValue = ˓ →5) aStatus[x] = 2 gui_setbtnpixmap(aBtns[x],Player2EatPic) lEat = True nPlayer2Score++ ok if (x != nPos) and (aStatus2[x] = 1) and (aStatusValues2[x] = nValue or nValue=5 ) aStatus2[x] = 2 gui_setbtnpixmap(aBtns2[x],Player2EatPic) lEat = True nPlayer2Score++ ok next if lEat nPlayer2Score++ gui_setbtnpixmap(aBtns2[nPos],Player2EatPic) aStatus2[nPos] = 2 label2.settext("Player (2) - Score : " + ˓ →nPlayer2Score) ok Func checknewgame if isnewgame() lnewgame = true if nPlayer1Score > nPlayer2Score label1.settext("Player (1) Wins!!!") ok if nPlayer2Score > nPlayer1Score label2.settext("Player (2) Wins!!!") ok app1.processEvents() delay(nDelayNewGame) win1.delete() app1.quit() ok Func isnewgame for t in aStatus if t = 0 return false ok next for t in aStatus2 if t = 0 return false ok next return true Func delay x nTime = x * 1000 (continues on next page) 45.57. The Cards Game 451
491.
Ring Documentation, Release1.16 (continued from previous page) oTest = new qTest oTest.qsleep(nTime) The application during the runtime Note: in the previous screen shot the player get the card number ‘5’ but his score is not increased because he opened this card while no other cards are visible! The next screen shot while running the game using a Mobile (Android) 45.57. The Cards Game 452
492.
Ring Documentation, Release1.16 Note: using Qt we can run the same application on other Mobile systems 45.58 Classes and their Methods to use the default events The next table present the class name and the methods that we have to use the default events. Class Name Methods to use the default Events QPushButton SetClickEvent() QAction SetClickEvent() QLineEdit SetTextChangedEvent() SetCursorPositionChangedEvent() SetEditingFinishedEvent() SetReturnPressedEvent() SetSelectionChangedEvent() SetTextEditedEvent() QTextEdit SetCopyAvailableEvent() SetCurrentCharFormatChangedEvent() SetCursorPositionChangedEvent() continues on next page 45.58. Classes and their Methods to use the default events 453
493.
Ring Documentation, Release1.16 Table 1 – continued from previous page Class Name Methods to use the default Events SetRedoAvailableEvent() SetSelectionChangedEvent() SetTextChangedEvent() SetUndoAvailableEvent() QListWidget SetCurrentItemChangedEvent() SetCurrentRowChangedEvent() SetCurrentTextChangedEvent() SetItemActivatedEvent() SetItemChangedEvent() SetItemClickedEvent() SetItemDoubleClickedEvent() SetItemEnteredEvent() SetItemPressedEvent() SetItemSelectionChangedEvent() QTreeView SetCollapseEvent() SetExpandedEvent() SetActivatedEvent() SetClickedEvent() SetDoubleClickedEvent() SetEnteredEvent() SetPressedEvent() SetViewportEnteredEvent() QTreeWidget SetCollapsedEvent() SetExpandedEvent() SetActivatedEvent() SetClickedEvent() SetDoubleClickedEvent() SetEnteredEvent() SetPressedEvent() SetViewportEnteredEvent() SetCurrentItemChangedEvent() SetItemActivatedEvent() SetItemChangedEvent() SetItemClickedEvent() SetItemCollapsedEvent() SetItemDoubleClickedEvent() SetItemEnteredEvent() SetItemExpandedEvent() SetItemPressedEvent() SetItemSelectionChangedEvent() QComboBox SetActivatedEvent() SetCurrentIndexChangedEvent() SetEditTextChangedEvent() SetHighlightedEvent() QTabWidget SetCurrentChangedEvent() SetTabCloseRequestedEvent() QTableWidget SetCellActivatedEvent() SetCellChangedEvent() SetCellClickedEvent() continues on next page 45.58. Classes and their Methods to use the default events 454
494.
Ring Documentation, Release1.16 Table 1 – continued from previous page Class Name Methods to use the default Events SetCellDoubleClickedEvent() SetCellEnteredEvent() SetCellPressedEvent() SetCurrentCellChangedEvent() SetCurrentItemChangedEvent() SetItemActivatedEvent() SetItemChangedEvent() SetItemClickedEvent() SetItemDoubleClickedEvent() SetItemEnteredEvent() SetItemPressedEvent() SetItemSelectionChangedEvent() QProgressBar SetValueChangedEvent() QSpinBox SetValueChangedEvent() QSlider SetActionTriggeredEvent() SetRangeChangedEvent() SetSliderMovedEvent() SetSliderPressedEvent() SetSliderReleasedEvent() SetValueChangedEvent() QDial SetActionTriggeredEvent() SetRangeChangedEvent() SetSliderMovedEvent() SetSliderPressedEvent() SetSliderReleasedEvent() SetValueChangedEvent() QWebView SetLoadFinishedEvent() SetLoadProgressEvent() SetLoadStartedEvent() SetSelectionChangedEvent() SetTitleChangedEvent() SetUrlChangedEvent() QCheckBox SetStateChangedEvent() SetClickedEvent() SetPressedEvent() SetReleasedEvent() SetToggledEvent() QRadioButton SetClickedEvent() SetPressedEvent() SetReleasedEvent() SetToggledEvent() QButtonGroup SetButtonClickedEvent() SetButtonPressedEvent() SetButtonReleasedEvent() QVideoWidget SetBrightnessChangedEvent() SetContrastChangedEvent() SetFullScreenChangedEvent() SetHueChangedEvent() SetSaturationChangedEvent() continues on next page 45.58. Classes and their Methods to use the default events 455
495.
Ring Documentation, Release1.16 Table 1 – continued from previous page Class Name Methods to use the default Events QTimer SetTimeoutEvent() QTcpServer SetAcceptErrorEvent() SetNewConnectionEvent() QIODevice SetAboutToCloseEvent() SetBytesWrittenEvent() SetReadChannelFinishedEvent() SetReadyReadEvent() QAbstractSocket SetConnectedEvent() SetDisconnectedEvent() SetErrorEvent() SetHostFoundEvent() SetProxyAuthenticationRequiredEvent() SetStateChangedEvent() QTcpSocket SetConnectedEvent() SetDisconnectedEvent() SetErrorEvent() SetHostFoundEvent() SetProxyAuthenticationRequiredEvent() SetStateChangedEvent() SetAboutToCloseEvent() SetBytesWrittenEvent() SetReadChannelFinishedEvent() SetReadyReadEvent() QColorDialog SetColorSelectedEvent() SetCurrentColorChangedEvent() QNetworkAccessManager SetFinishedEvent() QThread SetStartedEvent() SetFinishedEvent() 45.59 Methods to use Events with Events Filter RingQt define a new class called QAllEvents that help you in using Events Filter The next table presents the methods that we have Methods to get parameters Class Name getKeyCode() –> Number QAllEvents getx() –> Number gety() –> Number getglobalx() –> Number getglobaly() –> Number getbutton() –> Number getbuttons() –> Number The next table presents the methods that we have to use events. 45.59. Methods to use Events with Events Filter 456
496.
Ring Documentation, Release1.16 Method Name Class Name setKeyPressEvent(cEvent) QAllEvents setMouseButtonPressEvent(cEvent) setMouseButtonReleaseEvent(cEvent) setMouseButtonDblClickEvent(cEvent) setMouseMoveEvent(cEvent) setCloseEvent(cEvent) setContextMenuEvent(cEvent) setDragEnterEvent(cEvent) setDragLeaveEvent(cEvent) setDragMoveEvent(cEvent) setDropEvent(cEvent) setEnterEvent(cEvent) setFocusInEvent(cEvent) setFocusOutEvent(cEvent) setKeyReleaseEvent(cEvent) setLeaveEvent(cEvent) setNonClientAreaMouseButtonDblClickEvent(cEvent) setNonClientAreaMouseButtonPressEvent(cEvent) setNonClientAreaMouseButtonReleaseEvent(cEvent) setNonClientAreaMouseMoveEvent(cEvent) setMoveEvent(cEvent) setResizeEvent(cEvent) setWindowActivateEvent(cEvent) setWindowBlockedEvent(cEvent) setWindowDeactivateEvent(cEvent) setWindowStateChangeEvent(cEvent) setWindowUnblockedEvent(cEvent) 45.60 The Difference between Qt and RingQt (1) RingQt use simple methods to set the code that will be executed for events. Syntax: Set<Event_Name>Event(cEventCode) (2) RingQt change the name of some methods to avoid conflict with Ring Keywords. The next table present these little changes 45.60. The Difference between Qt and RingQt 457
497.
Ring Documentation, Release1.16 Class Name Qt Method Name RingQt Method Name QWebView load loadpage QMediaPlaylist load loadfile QMediaPlaylist next movenext QPainter end endpaint QPicture load loadfile QLineEdit end endtext QDialog done donedialog QTextDocument end enddoc QTextBlock next nextblock QSqlQuery next movenext QImage load loadimage QNetworkAccessManager get getvalue QNetworkAccessManager put putvalue QThread exit exitfromthread QRegularExpressionMatchIterator next nextitem QCamera load loadcamera 45.61 RingQt Classes and their Qt Documentation Qt Documentation : http://doc.qt.io/qt-5/classes.html See the “RingQt Classes and Methods Reference” chapter for supported classes and methods. 45.62 New Classes names - Index Start from 1 We added new classes to RingQt - another version of classes where the class names doesn’t start with the “q” letter Also updated methods so the index start from 1 when we deal with the GUI controls like • ComboBox • ListWidget • TableWidget • TreeWidget These classes are inside guilib.ring under the package name : System.GUI To use it load "guilib.ring" import System.GUI This doesn’t have any effect on our previous code, It’s just another choice for better code that is consistent with Ring rules. Also the form designer is updated to provide us the choice between using classes where (index start from 0) or (index start from 1) Example (Uses the Form Designer) (1) https://github.com/ring-lang/ring/blob/master/samples/UsingFormDesigner/indexstart/indexstartView.ring 45.61. RingQt Classes and their Qt Documentation 458
498.
Ring Documentation, Release1.16 (2) https://github.com/ring-lang/ring/blob/master/samples/UsingFormDesigner/indexstart/indexstartController.ring 45.63 Creating Reports using the WebLib and the GUILib The WebLib comes with a class called HtmlPage Using this class we can create reports quickly using WebLib & GUILib together Example: load "stdlib.ring" load "weblib.ring" load "guilib.ring" import System.Web import System.GUI new qApp { open_window(:CustomersReportController) exec() } class CustomersReportController from WindowsControllerParent oView = new CustomersReportView func Start CreateReport() func CreateReport mypage = new HtmlPage { h1 { text("Customers Report") } Table { style = stylewidth("100%") + stylegradient(4) TR { TD { WIDTH="10%" text("Customers Count : " ) } TD { text (100) } } } Table { style = stylewidth("100%") + stylegradient(26) TR { style = stylewidth("100%") + stylegradient(24) TD { text("Name " ) } TD { text("Age" ) } TD { text("Country" ) } TD { text("Job" ) } TD { text("Company" ) } } for x = 1 to 100 TR (continues on next page) 45.63. Creating Reports using the WebLib and the GUILib 459
499.
Ring Documentation, Release1.16 (continued from previous page) { TD { text("Test" ) } TD { text("30" ) } TD { text("Egypt" ) } TD { text("Sales" ) } TD { text("Future" ) } } next } } write("report.html",mypage.output()) func PrintEvent printer1 = new qPrinter(0) { setoutputformat(1) setoutputfilename("report.pdf") } oView { web.print(printer1, Method( :OpenPDF ) ) web.show() } func OpenPDF new QDesktopServices { OpenURL(new qURL("report.pdf") ) } class CustomersReportView win = new window() { setwindowtitle("Report Window") setgeometry(100,100,500,500) web = new webview(win) { setgeometry(100,100,1000,500) loadpage(new qurl("file:///"+ currentdir()+"/report.html")) } new pushbutton(win) { setGeometry(100,20,100,30) settext("Print") setclickevent(Method(:PrintEvent)) } showMaximized() } Screen Shot: 45.63. Creating Reports using the WebLib and the GUILib 460
CHAPTER FORTYSIX USING THE FORMDESIGNER In this chapter we will learn about using the Form Designer. We can run the From Designer from Ring Notepad From the Menubar in Ring Notepad - View Menu - We can Show/Hide the Form Designer window. Also we can run the Form Designer in another window. From the Ring Notepad - Tools Menu - Select the Form Designer. 462
502.
Ring Documentation, Release1.16 46.1 The Designer Windows • Toolbox : To select controls to be added to the window. • Properties : To set the properties of the active window or controls. • Design Region : To select, move and resize the window and the controls. 46.2 The Toolbox We have many buttons. • Lock : We can use it to draw many controls of the same type quickly. • Select : We can use it to select a control in the Design Region • Controls Buttons : Select a control to be added to the window. 46.3 The Properties • When we select the window or one control, We will have the selected object properties. • Also In the properties window we have a combobox to select the active control. • Some properties provide a button next to the property value. We can click on the button to get more options. • When we select more than one control, We will have options for multi-selection 46.1. The Designer Windows 463
503.
Ring Documentation, Release1.16 46.4 Running Forms When we save the form file (*.rform), The Form Designer will create two Ring files • The Controller Class • The View Class For example, if the form file is helloworld.rform The form designer will generate two files • helloworldcontroller.ring • helloworldview.ring To run the program, Open the controller class file then click the Run button (CTRL+F5) Tip: When you open a form using Ring Notepad, the controller class will be opened automatically, So we can press (CTRL+F5) or click on the Run button while the form designer window is active. 46.4. Running Forms 464
504.
Ring Documentation, Release1.16 46.5 Events Code (1) Just type the method name in the event property. This will add the next code to the Controller Class func CloseWindow oView { } (2) Then write the method code in the controller class. 46.5. Events Code 465
505.
Ring Documentation, Release1.16 In this example we write func CloseWindow oView.win.close() Where inside the controller class, We uses the oView object to access the form. Another Example : 46.5. Events Code 466
506.
Ring Documentation, Release1.16 The Event Code func SayHello oView { LineEdit2.setText("Hello "+ LineEdit1.text() ) } 46.6 Keyboard Shortcuts After selecting one or group of controls • Use the Arrows (Up, Down, Left and Right) to move them around. • Shift + the Arrows (Up, Down, Left and Right) to Resize the controls. • Del button to delete the controls. • CTRL+SHIFT+V to Duplicate the controls. 46.7 Menubar Designer From the Window properties we can open the Menubar Designer 46.6. Keyboard Shortcuts 467
507.
Ring Documentation, Release1.16 46.8 Window Flags From the Window properties we can open the Window Flags window. 46.8. Window Flags 468
508.
Ring Documentation, Release1.16 46.9 Entering Items For some controls like the List Widget we can enter items separated by comma ‘,’ 46.10 Using Layouts (1) To use layouts, At first add the layout control to the window. (2) Use the window “Set Layout” property to determine the main layout. (3) From the layout properties determine the controls and the layout type. 46.11 Objects Order and Layouts All the objects that are added to a layout must comes first! If we have a form that contains two buttons and a Layout Then adding a third button after creating the layout requires changing the objects order We can open the (Objects Order) window using a button from the (Properties) window 46.9. Entering Items 469
509.
Ring Documentation, Release1.16 Then we can select the (Button3) and click (Move Up) 46.11. Objects Order and Layouts 470
510.
Ring Documentation, Release1.16 Then we close the (Objects Order) window 46.11. Objects Order and Layouts 471
511.
Ring Documentation, Release1.16 46.12 More Samples and Tests Check the folder : ring/samples/UsingFormDesigner Online : https://github.com/ring-lang/ring/tree/master/samples/UsingFormDesigner 46.12. More Samples and Tests 472
512.
CHAPTER FORTYSEVEN GRAPHICS PROGRAMMING USINGRINGQT3D In this chapter we will learn how to use Qt3D through many samples. 47.1 Drawing Cube load "guilib.ring" new qApp { oView = new Qt3dwindow() oWidget = new QWidget() oContainer = oWidget.createWindowContainer(oView,oWidget,0) oRootEntity = new QEntity(oContainer) oInput = new QInputAspect(oRootEntity) oView.registerAspect(oInput) oCameraEntity = oView.Camera() oCameraEntity.lens().setPerspectiveProjection(45.0, 16.0/9.0, 0.1, 1000.0) oCameraEntity.setPosition(new QVector3D(0, 0, 20.0)) oCameraEntity.setUpVector(new QVector3D(0, 1, 0)) oCameraEntity.setViewCenter(new QVector3D(0, 0, 0)) oLightEntity = new QEntity(oRootEntity) oLight = new QPointLight(oLightEntity) oLight.setColor(new QColor() { setRGB(255,255,255,255) }) oLight.setIntensity(1) oLightEntity.addComponent(oLight) oLightTransform = new QTransform(oLightEntity) oLightTransform.setTranslation(oCameraEntity.position()) oLightEntity.addComponent(oLightTransform) oCamController = new QFirstPersonCameraController(oRootEntity) oCamController.setCamera(oCameraEntity) oCube = new QCuboidMesh(oRootEntity) { setXextent(2) setYextent(2) (continues on next page) 473
513.
Ring Documentation, Release1.16 (continued from previous page) setZextent(3) } oCubeTransform = new QTransform(oCube) oCubeTransform.setScale(2) oCubeTransform.setTranslation(new QVector3D(3, 3, 3)) oCubeMaterial = new QPhongMaterial(oCube) oCubeMaterial.setDiffuse(new QColor() {setRGB(200,100,100,100)}) oCubeEntity = new QEntity(oRootEntity) oCubeEntity.addComponent(oCube) oCubeEntity.addComponent(oCubeMaterial) oCubeEntity.addComponent(oCubeTransform) oView.setRootEntity(oRootEntity) oLayout = new QVBoxLayout() oLayout.AddWidget(oContainer) oWidget { setwindowtitle("Using Qt3D - Cube") resize(800,600) setLayout(oLayout) showMaximized() } exec() } 47.1. Drawing Cube 474
514.
Ring Documentation, Release1.16 47.2 Drawing Torus load "guilib.ring" new qApp { oView = new Qt3dwindow() oWidget = new QWidget() oContainer = oWidget.createWindowContainer(oView,oWidget,0) oRootEntity = new QEntity(oContainer) oInput = new QInputAspect(oRootEntity) oView.registerAspect(oInput) oCameraEntity = oView.Camera() oCameraEntity.lens().setPerspectiveProjection(45.0, 16.0/9.0, 0.1, 1000.0) oCameraEntity.setPosition(new QVector3D(0, 0, 20.0)) oCameraEntity.setUpVector(new QVector3D(0, 1, 0)) oCameraEntity.setViewCenter(new QVector3D(0, 0, 0)) oLightEntity = new QEntity(oRootEntity) oLight = new QPointLight(oLightEntity) oLight.setColor(new QColor() { setRGB(255,255,255,255) }) oLight.setIntensity(1) oLightEntity.addComponent(oLight) oLightTransform = new QTransform(oLightEntity) oLightTransform.setTranslation(oCameraEntity.position()) oLightEntity.addComponent(oLightTransform) oCamController = new QFirstPersonCameraController(oRootEntity) oCamController.setCamera(oCameraEntity) oTorus = new QTorusMesh(oRootEntity) oTorus.setRadius(1.0) oTorus.setMinorRadius(0.4) oTorus.setRings(100) oTorus.setSlices(20) oTorusTransform = new QTransform(oTorus) oTorusTransform.setScale(2) oTorusTransform.setTranslation(new QVector3D(3, 3, 3)) oTorusMaterial = new QPhongMaterial(oTorus) oTorusMaterial.setDiffuse(new QColor() {setRGB(200,100,100,100)}) oTorusEntity = new QEntity(oRootEntity) oTorusEntity.addComponent(oTorus) oTorusEntity.addComponent(oTorusMaterial) oTorusEntity.addComponent(oTorusTransform) oView.setRootEntity(oRootEntity) oLayout = new QVBoxLayout() (continues on next page) 47.2. Drawing Torus 475
515.
Ring Documentation, Release1.16 (continued from previous page) oLayout.AddWidget(oContainer) oWidget { setwindowtitle("Using Qt3D - Torus") resize(800,600) setLayout(oLayout) showMaximized() } exec() } 47.3 Drawing Sphere load "guilib.ring" new qApp { oView = new Qt3dwindow() oWidget = new QWidget() oContainer = oWidget.createWindowContainer(oView,oWidget,0) oRootEntity = new QEntity(oContainer) (continues on next page) 47.3. Drawing Sphere 476
516.
Ring Documentation, Release1.16 (continued from previous page) oInput = new QInputAspect(oRootEntity) oView.registerAspect(oInput) oCameraEntity = oView.Camera() oCameraEntity.lens().setPerspectiveProjection(45.0, 16.0/9.0, 0.1, 1000.0) oCameraEntity.setPosition(new QVector3D(0, 0, 20.0)) oCameraEntity.setUpVector(new QVector3D(0, 1, 0)) oCameraEntity.setViewCenter(new QVector3D(0, 0, 0)) oLightEntity = new QEntity(oRootEntity) oLight = new QPointLight(oLightEntity) oLight.setColor(new QColor() { setRGB(255,255,255,255) }) oLight.setIntensity(1) oLightEntity.addComponent(oLight) oLightTransform = new QTransform(oLightEntity) oLightTransform.setTranslation(oCameraEntity.position()) oLightEntity.addComponent(oLightTransform) oCamController = new QFirstPersonCameraController(oRootEntity) oCamController.setCamera(oCameraEntity) oSphere = new QSphereMesh(oRootEntity) oSphere.setRadius(1.0) oSphere.setRings(100) oSphere.setSlices(20) oSphereTransform = new QTransform(oSphere) oSphereTransform.setScale(2) oSphereTransform.setTranslation(new QVector3D(3, 3, 3)) oSphereMaterial = new QPhongMaterial(oSphere) oSphereMaterial.setDiffuse(new QColor() {setRGB(200,100,100,100)}) oSphereEntity = new QEntity(oRootEntity) oSphereEntity.addComponent(oSphere) oSphereEntity.addComponent(oSphereMaterial) oSphereEntity.addComponent(oSphereTransform) oView.setRootEntity(oRootEntity) oLayout = new QVBoxLayout() oLayout.AddWidget(oContainer) oWidget { setwindowtitle("Using Qt3D - Sphere") resize(800,600) setLayout(oLayout) showMaximized() } exec() } 47.3. Drawing Sphere 477
517.
Ring Documentation, Release1.16 47.4 Drawing Cylinder load "guilib.ring" new qApp { oView = new Qt3dwindow() oWidget = new QWidget() oContainer = oWidget.createWindowContainer(oView,oWidget,0) oRootEntity = new QEntity(oContainer) oInput = new QInputAspect(oRootEntity) oView.registerAspect(oInput) oCameraEntity = oView.Camera() oCameraEntity.lens().setPerspectiveProjection(45.0, 16.0/9.0, 0.1, 1000.0) oCameraEntity.setPosition(new QVector3D(0, 0, 20.0)) oCameraEntity.setUpVector(new QVector3D(0, 1, 0)) oCameraEntity.setViewCenter(new QVector3D(0, 0, 0)) oLightEntity = new QEntity(oRootEntity) oLight = new QPointLight(oLightEntity) oLight.setColor(new QColor() { setRGB(255,255,255,255) }) oLight.setIntensity(1) oLightEntity.addComponent(oLight) oLightTransform = new QTransform(oLightEntity) (continues on next page) 47.4. Drawing Cylinder 478
518.
Ring Documentation, Release1.16 (continued from previous page) oLightTransform.setTranslation(oCameraEntity.position()) oLightEntity.addComponent(oLightTransform) oCamController = new QFirstPersonCameraController(oRootEntity) oCamController.setCamera(oCameraEntity) oCylinder = new QCylinderMesh(oRootEntity) oCylinder.setRadius(1) oCylinder.setRings(100) oCylinder.setSlices(20) oCylinder.setLength(5) oCylinderTransform = new QTransform(oCylinder) oCylinderTransform.setScale(2) oCylinderTransform.setTranslation(new QVector3D(1, 0, 3)) oCylinderMaterial = new QPhongMaterial(oCylinder) oCylinderMaterial.setDiffuse(new QColor() {setRGB(200,100,100,100)}) oCylinderEntity = new QEntity(oRootEntity) oCylinderEntity.addComponent(oCylinder) oCylinderEntity.addComponent(oCylinderMaterial) oCylinderEntity.addComponent(oCylinderTransform) oView.setRootEntity(oRootEntity) oLayout = new QVBoxLayout() oLayout.AddWidget(oContainer) oWidget { setwindowtitle("Using Qt3D - Cylinder") resize(800,600) setLayout(oLayout) showMaximized() } exec() } 47.4. Drawing Cylinder 479
519.
Ring Documentation, Release1.16 47.5 Drawing Cone load "guilib.ring" new qApp { oView = new Qt3dwindow() oWidget = new QWidget() oContainer = oWidget.createWindowContainer(oView,oWidget,0) oRootEntity = new QEntity(oContainer) oInput = new QInputAspect(oRootEntity) oView.registerAspect(oInput) oCameraEntity = oView.Camera() oCameraEntity.lens().setPerspectiveProjection(45.0, 16.0/9.0, 0.1, 1000.0) oCameraEntity.setPosition(new QVector3D(0, 0, 20.0)) oCameraEntity.setUpVector(new QVector3D(0, 1, 0)) oCameraEntity.setViewCenter(new QVector3D(0, 0, 0)) oLightEntity = new QEntity(oRootEntity) oLight = new QPointLight(oLightEntity) oLight.setColor(new QColor() { setRGB(255,255,255,255) }) oLight.setIntensity(1) oLightEntity.addComponent(oLight) oLightTransform = new QTransform(oLightEntity) (continues on next page) 47.5. Drawing Cone 480
520.
Ring Documentation, Release1.16 (continued from previous page) oLightTransform.setTranslation(oCameraEntity.position()) oLightEntity.addComponent(oLightTransform) oCamController = new QFirstPersonCameraController(oRootEntity) oCamController.setCamera(oCameraEntity) oCone = new QConeMesh(oRootEntity) oCone.setRings(100) oCone.setSlices(20) oCone.setLength(5) oConeTransform = new QTransform(oCone) oConeTransform.setScale(2) oConeTransform.setTranslation(new QVector3D(1, 0, 3)) oConeMaterial = new QPhongMaterial(oCone) oConeMaterial.setDiffuse(new QColor() {setRGB(200,100,100,100)}) oConeEntity = new QEntity(oRootEntity) oConeEntity.addComponent(oCone) oConeEntity.addComponent(oConeMaterial) oConeEntity.addComponent(oConeTransform) oView.setRootEntity(oRootEntity) oLayout = new QVBoxLayout() oLayout.AddWidget(oContainer) oWidget { setwindowtitle("Using Qt3D - Cone") resize(800,600) setLayout(oLayout) showMaximized() } exec() } 47.5. Drawing Cone 481
521.
Ring Documentation, Release1.16 47.6 Drawing Plane load "guilib.ring" new qApp { oView = new Qt3dwindow() oWidget = new QWidget() oContainer = oWidget.createWindowContainer(oView,oWidget,0) oRootEntity = new QEntity(oContainer) oInput = new QInputAspect(oRootEntity) oView.registerAspect(oInput) oCameraEntity = oView.Camera() oCameraEntity.lens().setPerspectiveProjection(45.0, 16.0/9.0, 0.1, 1000.0) oCameraEntity.setPosition(new QVector3D(0, 0, 20.0)) oCameraEntity.setUpVector(new QVector3D(0, 1, 0)) oCameraEntity.setViewCenter(new QVector3D(0, 0, 0)) oLightEntity = new QEntity(oRootEntity) oLight = new QPointLight(oLightEntity) oLight.setColor(new QColor() { setRGB(255,255,255,255) }) oLight.setIntensity(1) oLightEntity.addComponent(oLight) oLightTransform = new QTransform(oLightEntity) (continues on next page) 47.6. Drawing Plane 482
522.
Ring Documentation, Release1.16 (continued from previous page) oLightTransform.setTranslation(oCameraEntity.position()) oLightEntity.addComponent(oLightTransform) oCamController = new QFirstPersonCameraController(oRootEntity) oCamController.setCamera(oCameraEntity) oPlane = new QPlaneMesh(oRootEntity) oPlane.setHeight(5) oPlane.setWidth(5) oPlane.setmeshresolution(new qSize(10,10)) oPlaneTransform = new QTransform(oPlane) oPlaneTransform.setScale(2) oPlaneTransform.setTranslation(new QVector3D(0, -4, 4)) oPlaneMaterial = new QPhongMaterial(oPlane) oPlaneMaterial.setDiffuse(new QColor() {setRGB(200,100,100,100)}) oPlaneEntity = new QEntity(oRootEntity) oPlaneEntity.addComponent(oPlane) oPlaneEntity.addComponent(oPlaneMaterial) oPlaneEntity.addComponent(oPlaneTransform) oView.setRootEntity(oRootEntity) oLayout = new QVBoxLayout() oLayout.AddWidget(oContainer) oWidget { setwindowtitle("Using Qt3D - Plane") resize(800,600) setLayout(oLayout) showMaximized() } exec() } 47.6. Drawing Plane 483
523.
Ring Documentation, Release1.16 47.7 Texture load "guilib.ring" new qApp { oView = new Qt3dwindow() oWidget = new QWidget() oContainer = oWidget.createWindowContainer(oView,oWidget,0) oRootEntity = new QEntity(oContainer) oInput = new QInputAspect(oRootEntity) oView.registerAspect(oInput) oCameraEntity = oView.Camera() oCameraEntity.lens().setPerspectiveProjection(45.0, 16.0/9.0, 0.1, 1000.0) oCameraEntity.setPosition(new QVector3D(0, 0, 20.0)) oCameraEntity.setUpVector(new QVector3D(0, 1, 0)) oCameraEntity.setViewCenter(new QVector3D(0, 0, 0)) oLightEntity = new QEntity(oRootEntity) oLight = new QPointLight(oLightEntity) oLight.setColor(new QColor() { setRGB(255,255,255,255) }) oLight.setIntensity(1) oLightEntity.addComponent(oLight) oLightTransform = new QTransform(oLightEntity) oLightTransform.setTranslation(oCameraEntity.position()) oLightEntity.addComponent(oLightTransform) (continues on next page) 47.7. Texture 484
524.
Ring Documentation, Release1.16 (continued from previous page) oCamController = new QFirstPersonCameraController(oRootEntity) oCamController.setCamera(oCameraEntity) oCube = new QCuboidMesh(oRootEntity) { setXextent(2) setYextent(2) setZextent(3) } oCubeTransform = new QTransform(oCube) oCubeTransform.setScale(2) oCubeTransform.setTranslation(new QVector3D(3, 3, 3)) oTextureLoader = new QTextureLoader(oCube); oTextureLoader.setSource( new QUrl("file:///"+currentdir()+"/assets/texture/gold.jpg") ) oCubeMaterial = new QTextureMaterial(oCube) oCubeMaterial.setTexture(oTextureLoader) oCubeEntity = new QEntity(oRootEntity) oCubeEntity.addComponent(oCube) oCubeEntity.addComponent(oCubeMaterial) oCubeEntity.addComponent(oCubeTransform) oView.setRootEntity(oRootEntity) oLayout = new QVBoxLayout() oLayout.AddWidget(oContainer) oWidget { setwindowtitle("Using Qt3D - Adding Texture") resize(800,600) setLayout(oLayout) showMaximized() } exec() } 47.7. Texture 485
525.
Ring Documentation, Release1.16 47.8 Key Press load "guilib.ring" new qApp { oView = new Qt3dwindow() oWidget = new QWidget() oContainer = oWidget.createWindowContainer(oView,oWidget,0) oRootEntity = new QEntity(oContainer) oFilter = new qallevents(oView) oFilter.setKeyPressEvent("pKeyPress()") oView.installeventfilter(oFilter) oInput = new QInputAspect(oRootEntity) oView.registerAspect(oInput) oCameraEntity = oView.Camera() oCameraEntity.lens().setPerspectiveProjection(45.0, 16.0/9.0, 0.1, 1000.0) oCameraEntity.setPosition(new QVector3D(0, 0, 20.0)) oCameraEntity.setUpVector(new QVector3D(0, 1, 0)) oCameraEntity.setViewCenter(new QVector3D(0, 0, 0)) oLightEntity = new QEntity(oRootEntity) oLight = new QPointLight(oLightEntity) oLight.setColor(new QColor() { setRGB(255,255,255,255) }) oLight.setIntensity(1) oLightEntity.addComponent(oLight) (continues on next page) 47.8. Key Press 486
526.
Ring Documentation, Release1.16 (continued from previous page) oLightTransform = new QTransform(oLightEntity) oLightTransform.setTranslation(oCameraEntity.position()) oLightEntity.addComponent(oLightTransform) oCamController = new QFirstPersonCameraController(oRootEntity) oCamController.setCamera(oCameraEntity) oCamController.setEnabled(False) oCube = new QCuboidMesh(oRootEntity) { setXextent(2) setYextent(2) setZextent(3) } oCubeTransform = new QTransform(oCube) oCubeTransform.setScale(2) oCubeTransform.setTranslation(new QVector3D(3, 3, 3)) oTextureLoader = new QTextureLoader(oCube); oTextureLoader.setSource( new QUrl("file:///"+currentdir()+"/assets/texture/gold.jpg") ) oCubeMaterial = new QTextureMaterial(oCube) oCubeMaterial.setTexture(oTextureLoader) oCubeEntity = new QEntity(oRootEntity) oCubeEntity.addComponent(oCube) oCubeEntity.addComponent(oCubeMaterial) oCubeEntity.addComponent(oCubeTransform) oView.setRootEntity(oRootEntity) oLayout = new QVBoxLayout() oLayout.AddWidget(oContainer) oWidget { setwindowtitle("Using Qt3D - Moving Cube using the Keyboard") resize(800,600) setLayout(oLayout) showMaximized() } oContainer.setfocus(0) exec() } func pKeyPress nKey = oFilter.getkeycode() oX = oCubeTransform.translation().x() oY = oCubeTransform.translation().y() oZ = oCubeTransform.translation().z() switch nKey on Qt_Key_Right oX++ on Qt_Key_Left oX-- on Qt_Key_Up (continues on next page) 47.8. Key Press 487
527.
Ring Documentation, Release1.16 (continued from previous page) oY++ on Qt_Key_Down oY-- off oCubeTransform.setTranslation(new QVector3D(oX, oY, oZ)) 47.9 Object Picker load "guilib.ring" new qApp { oView = new Qt3dwindow() oWidget = new QWidget() oContainer = oWidget.createWindowContainer(oView,oWidget,0) oRootEntity = new QEntity(oContainer) oFilter = new qallevents(oView) oFilter.setKeyPressEvent("pKeyPress()") oView.installeventfilter(oFilter) oInput = new QInputAspect(oRootEntity) (continues on next page) 47.9. Object Picker 488
528.
Ring Documentation, Release1.16 (continued from previous page) oView.registerAspect(oInput) oCameraEntity = oView.Camera() oCameraEntity.lens().setPerspectiveProjection(45.0, 16.0/9.0, 0.1, 1000.0) oCameraEntity.setPosition(new QVector3D(0, 0, 20.0)) oCameraEntity.setUpVector(new QVector3D(0, 1, 0)) oCameraEntity.setViewCenter(new QVector3D(0, 0, 0)) oLightEntity = new QEntity(oRootEntity) oLight = new QPointLight(oLightEntity) oLight.setColor(new QColor() { setRGB(255,255,255,255) }) oLight.setIntensity(1) oLightEntity.addComponent(oLight) oLightTransform = new QTransform(oLightEntity) oLightTransform.setTranslation(oCameraEntity.position()) oLightEntity.addComponent(oLightTransform) oCamController = new QFirstPersonCameraController(oRootEntity) oCamController.setCamera(oCameraEntity) oCamController.setEnabled(False) oCube = new QCuboidMesh(oRootEntity) { setXextent(2) setYextent(2) setZextent(3) } oCubeTransform = new QTransform(oCube) oCubeTransform.setScale(2) oCubeTransform.setTranslation(new QVector3D(3, 3, 3)) oTextureLoader = new QTextureLoader(oCube); oTextureLoader.setSource( new QUrl("file:///"+currentdir()+"/assets/texture/gold.jpg") ) oCubeMaterial = new QTextureMaterial(oCube) oCubeMaterial.setTexture(oTextureLoader) oCubeEntity = new QEntity(oRootEntity) oCubeEntity.addComponent(oCube) oCubeEntity.addComponent(oCubeMaterial) oCubeEntity.addComponent(oCubeTransform) oPicker = new qObjectPicker(oCube) { setclickedevent("pClick()") } oCubeEntity.addComponent(oPicker) oView.setRootEntity(oRootEntity) oLayout = new QVBoxLayout() oLayout.AddWidget(oContainer) oWidget { setwindowtitle("Using Qt3D - Object Picker - Click on the Cube") resize(800,600) (continues on next page) 47.9. Object Picker 489
529.
Ring Documentation, Release1.16 (continued from previous page) setLayout(oLayout) showMaximized() } oContainer.setfocus(0) exec() } func pKeyPress nKey = oFilter.getkeycode() oX = oCubeTransform.translation().x() oY = oCubeTransform.translation().y() oZ = oCubeTransform.translation().z() switch nKey on Qt_Key_Right oX++ on Qt_Key_Left oX-- on Qt_Key_Up oY++ on Qt_Key_Down oY-- off oCubeTransform.setTranslation(new QVector3D(oX, oY, oZ)) func pClick msginfo("Event","Click") oContainer.setfocus(0) 47.9. Object Picker 490
530.
Ring Documentation, Release1.16 47.10 Frame Action load "guilib.ring" new qApp { oView = new Qt3dwindow() oWidget = new QWidget() oContainer = oWidget.createWindowContainer(oView,oWidget,0) oRootEntity = new QEntity(oContainer) oInput = new QInputAspect(oRootEntity) oView.registerAspect(oInput) oCameraEntity = oView.Camera() oCameraEntity.lens().setPerspectiveProjection(45.0, 16.0/9.0, 0.1, 1000.0) oCameraEntity.setPosition(new QVector3D(0, 0, 20.0)) (continues on next page) 47.10. Frame Action 491
531.
Ring Documentation, Release1.16 (continued from previous page) oCameraEntity.setUpVector(new QVector3D(0, 1, 0)) oCameraEntity.setViewCenter(new QVector3D(0, 0, 0)) oLightEntity = new QEntity(oRootEntity) oLight = new QPointLight(oLightEntity) oLight.setColor(new QColor() { setRGB(255,255,255,255) }) oLight.setIntensity(1) oLightEntity.addComponent(oLight) oLightTransform = new QTransform(oLightEntity) oLightTransform.setTranslation(oCameraEntity.position()) oLightEntity.addComponent(oLightTransform) oCamController = new QFirstPersonCameraController(oRootEntity) oCamController.setCamera(oCameraEntity) oCamController.setEnabled(False) oCube = new QCuboidMesh(oRootEntity) { setXextent(1) setYextent(1) setZextent(1) } oCubeTransform = new QTransform(oCube) oCubeTransform.setScale(2) oCubeTransform.setTranslation(new QVector3D(-5, -5, -5)) oTextureLoader = new QTextureLoader(oCube); oTextureLoader.setSource( new QUrl("file:///"+currentdir()+"/assets/texture/gold.jpg") ) oCubeMaterial = new QTextureMaterial(oCube) oCubeMaterial.setTexture(oTextureLoader) oCubeEntity = new QEntity(oRootEntity) oCubeEntity.addComponent(oCube) oCubeEntity.addComponent(oCubeMaterial) oCubeEntity.addComponent(oCubeTransform) nAngle=0 nSpeed=0.1 oFrameAction = new qFrameAction(oRootEntity) { settriggeredevent("pEvent()") } oView.setRootEntity(oRootEntity) oLayout = new QVBoxLayout() oLayout.AddWidget(oContainer) oWidget { setwindowtitle("Using Qt3D - Frame Action") resize(800,600) setLayout(oLayout) showMaximized() } exec() } (continues on next page) 47.10. Frame Action 492
532.
Ring Documentation, Release1.16 (continued from previous page) func pEvent # Move the Cube oX = oCubeTransform.translation().x() oY = oCubeTransform.translation().y() oZ = oCubeTransform.translation().z() if oX >= 4 nSpeed=-0.1 but oX <= -10 nSpeed=0.1 ok oCubeTransform.setTranslation( new QVector3D(oX+nSpeed, oY+nSpeed, oZ+nSpeed)) # Rotate the Cube nAngle+=5 if nAngle=360 nAngle=0 ok oQ = new QQuaternion(0,0,0,0) oCubeTransform.setRotation( oQ.fromAxisAndAngle(new QVector3D(0, 1, 0), nAngle)) 47.10. Frame Action 493
533.
Ring Documentation, Release1.16 47.11 Text 2D load "guilib.ring" new qApp { oView = new Qt3dwindow() oWidget = new QWidget() oContainer = oWidget.createWindowContainer(oView,oWidget,0) oRootEntity = new QEntity(oContainer) oView.defaultframegraph().setclearcolor(new QColor() {setRGB(100,250,150,255)} ˓ →) oInput = new QInputAspect(oRootEntity) oView.registerAspect(oInput) oCameraEntity = oView.Camera() oCameraEntity.lens().setPerspectiveProjection(45.0, 16.0/9.0, 0.1, 1000.0) oCameraEntity.setPosition(new QVector3D(0, 0, 20.0)) oCameraEntity.setUpVector(new QVector3D(0, 1, 0)) oCameraEntity.setViewCenter(new QVector3D(0, 0, 0)) oLightEntity = new QEntity(oRootEntity) oLight = new QPointLight(oLightEntity) oLight.setColor(new QColor() { setRGB(255,255,255,255) }) oLight.setIntensity(1) oLightEntity.addComponent(oLight) oLightTransform = new QTransform(oLightEntity) oLightTransform.setTranslation(oCameraEntity.position()) oLightEntity.addComponent(oLightTransform) oCamController = new QFirstPersonCameraController(oRootEntity) oCamController.setCamera(oCameraEntity) oCube = new QCuboidMesh(oRootEntity) { setXextent(2) setYextent(2) setZextent(3) } oCubeTransform = new QTransform(oCube) oCubeTransform.setScale(2) oCubeTransform.setTranslation(new QVector3D(0, 3, 4)) oTextureLoader = new QTextureLoader(oCube); oTextureLoader.setSource( new QUrl("file:///"+currentdir()+"/assets/texture/ring.bmp") ) oCubeMaterial = new QTextureMaterial(oCube) oCubeMaterial.setTexture(oTextureLoader) oCubeEntity = new QEntity(oRootEntity) oCubeEntity.addComponent(oCube) (continues on next page) 47.11. Text 2D 494
534.
Ring Documentation, Release1.16 (continued from previous page) oCubeEntity.addComponent(oCubeMaterial) oCubeEntity.addComponent(oCubeTransform) oText2DEntity = new QText2DEntity(oRootEntity) { setText("Ring programming language") setWidth(400) setHeight(40) setColor(new QColor() {setRGB(128,128,128,255)}) } oText2DTransform = new QTransform(oText2DEntity) oText2DTransform.setScale(0.1) oText2DTransform.setTranslation(new QVector3D(-10.5, -5, 0)) oText2DEntity.addComponent(oText2DTransform) oView.setRootEntity(oRootEntity) oLayout = new QVBoxLayout() oLayout.AddWidget(oContainer) oWidget { setwindowtitle("Using Qt3D - Text2D") resize(800,600) setLayout(oLayout) showMaximized() } exec() } 47.11. Text 2D 495
535.
Ring Documentation, Release1.16 47.12 Extruded Text load "guilib.ring" new qApp { oView = new Qt3dwindow() oWidget = new QWidget() oContainer = oWidget.createWindowContainer(oView,oWidget,0) oRootEntity = new QEntity(oContainer) oView.defaultframegraph().setclearcolor(new QColor() {setRGB(100,250,150,255)} ˓ →) oInput = new QInputAspect(oRootEntity) oView.registerAspect(oInput) oCameraEntity = oView.Camera() oCameraEntity.lens().setPerspectiveProjection(45.0, 16.0/9.0, 0.1, 1000.0) oCameraEntity.setPosition(new QVector3D(0, 0, 20.0)) oCameraEntity.setUpVector(new QVector3D(0, 1, 0)) oCameraEntity.setViewCenter(new QVector3D(0, 0, 0)) oLightEntity = new QEntity(oRootEntity) oLight = new QPointLight(oLightEntity) oLight.setColor(new QColor() { setRGB(255,255,255,255) }) oLight.setIntensity(1) oLightEntity.addComponent(oLight) oLightTransform = new QTransform(oLightEntity) oLightTransform.setTranslation(oCameraEntity.position()) oLightEntity.addComponent(oLightTransform) oCamController = new QFirstPersonCameraController(oRootEntity) oCamController.setCamera(oCameraEntity) oCube = new QCuboidMesh(oRootEntity) { setXextent(2) setYextent(2) setZextent(3) } oCubeTransform = new QTransform(oCube) oCubeTransform.setScale(2) oCubeTransform.setTranslation(new QVector3D(0, 3, 4)) oTextureLoader = new QTextureLoader(oCube); oTextureLoader.setSource( new QUrl("file:///"+currentdir()+"/assets/texture/ring.bmp") ) oCubeMaterial = new QTextureMaterial(oCube) oCubeMaterial.setTexture(oTextureLoader) oCubeEntity = new QEntity(oRootEntity) oCubeEntity.addComponent(oCube) (continues on next page) 47.12. Extruded Text 496
536.
Ring Documentation, Release1.16 (continued from previous page) oCubeEntity.addComponent(oCubeMaterial) oCubeEntity.addComponent(oCubeTransform) oTextEntity = new QEntity(oRootEntity) oTextMesh = new QExtrudedTextMesh(oTextEntity) { setText("Ring") } oTextTransform = new QTransform(oTextEntity) oTextTransform.setScale(3) oTextTransform.setTranslation(new QVector3D(-5.5, -4, 3)) oTextMaterial = new QPhongMaterial(oTextEntity); oTextMaterial.setDiffuse(new QColor() {setRGB(0,0,255,255)}) oTextEntity.addComponent(oTextMesh) oTextEntity.addComponent(oTextTransform) oTextEntity.addComponent(oTextMaterial) oView.setRootEntity(oRootEntity) oLayout = new QVBoxLayout() oLayout.AddWidget(oContainer) oWidget { setwindowtitle("Using Qt3D - Extruded Text") resize(800,600) setLayout(oLayout) showMaximized() } exec() } 47.12. Extruded Text 497
537.
Ring Documentation, Release1.16 47.13 Model load "guilib.ring" new qApp { oView = new Qt3dwindow() oWidget = new QWidget() oContainer = oWidget.createWindowContainer(oView,oWidget,0) oRootEntity = new QEntity(oContainer) oInput = new QInputAspect(oRootEntity) oView.registerAspect(oInput) oCameraEntity = oView.Camera() oCameraEntity.lens().setPerspectiveProjection(45.0, 16.0/9.0, 0.1, 1000.0) oCameraEntity.setPosition(new QVector3D(0, 0, 20.0)) oCameraEntity.setUpVector(new QVector3D(0, 1, 0)) oCameraEntity.setViewCenter(new QVector3D(0, 0, 0)) oLightEntity = new QEntity(oRootEntity) oLight = new QPointLight(oLightEntity) oLight.setColor(new QColor() { setRGB(255,255,255,255) }) oLight.setIntensity(1) oLightEntity.addComponent(oLight) oLightTransform = new QTransform(oLightEntity) oLightTransform.setTranslation(oCameraEntity.position()) oLightEntity.addComponent(oLightTransform) oCamController = new QFirstPersonCameraController(oRootEntity) oCamController.setCamera(oCameraEntity) oModel = new qmesh(oRootEntity) oModel.setsource( new qURL("file:///"+currentdir()+"/assets/model/lucky_cat.obj") ) oModelTransform = new QTransform(oModel) oModelTransform.setScale(0.1) oModelTransform.setTranslation(new QVector3D(0, 0, 0)) oQ = new QQuaternion(0,0,0,0) oModelTransform.setRotation(oQ.fromAxisAndAngle(new QVector3D(0, 1, 0), 180)) oModelMaterial = new QPhongMaterial(oModel) oModelMaterial.setDiffuse(new QColor() {setRGB(0,255,128,255)}) oModelEntity = new QEntity(oRootEntity) oModelEntity.addComponent(oModel) oModelEntity.addComponent(oModelmaterial) oModelEntity.addComponent(oModelTransform) oView.setRootEntity(oRootEntity) (continues on next page) 47.13. Model 498
538.
Ring Documentation, Release1.16 (continued from previous page) oLayout = new QVBoxLayout() oLayout.AddWidget(oContainer) oWidget { setwindowtitle("Using Qt3D - Model (Obj File)") resize(800,600) setLayout(oLayout) showMaximized() } exec() } 47.14 Model Texture load "guilib.ring" new qApp { oView = new Qt3dwindow() oWidget = new QWidget() oContainer = oWidget.createWindowContainer(oView,oWidget,0) oRootEntity = new QEntity(oContainer) oInput = new QInputAspect(oRootEntity) oView.registerAspect(oInput) oCameraEntity = oView.Camera() (continues on next page) 47.14. Model Texture 499
539.
Ring Documentation, Release1.16 (continued from previous page) oCameraEntity.lens().setPerspectiveProjection(45.0, 16.0/9.0, 0.1, 1000.0) oCameraEntity.setPosition(new QVector3D(0, 0, 20.0)) oCameraEntity.setUpVector(new QVector3D(0, 1, 0)) oCameraEntity.setViewCenter(new QVector3D(0, 25, 0)) oLightEntity = new QEntity(oRootEntity) oLight = new QPointLight(oLightEntity) oLight.setColor(new QColor() { setRGB(255,255,255,255) }) oLight.setIntensity(1) oLightEntity.addComponent(oLight) oLightTransform = new QTransform(oLightEntity) oLightTransform.setTranslation(oCameraEntity.position()) oLightEntity.addComponent(oLightTransform) oCamController = new QFirstPersonCameraController(oRootEntity) oCamController.setCamera(oCameraEntity) oModel = new qmesh(oRootEntity) oModel.setsource( new qURL("file:///"+currentdir()+"/assets/model/Robot.obj") ) oModelTransform = new QTransform(oModel) oModelTransform.setScale(0.5) oModelTransform.setTranslation(new QVector3D(0, 12, 4)) oLoader = new QTextureLoader(oModel) oModelMaterial = new QTextureMaterial(oModel) oLoader.setSource( new QUrl("file:///"+currentdir()+"/assets/texture/Robot.jpg") ) oModelMaterial.setTexture(oLoader) oModelEntity = new QEntity(oRootEntity) oModelEntity.addComponent(oModel) oModelEntity.addComponent(oModelMaterial) oModelEntity.addComponent(oModelTransform) oView.setRootEntity(oRootEntity) oLayout = new QVBoxLayout() oLayout.AddWidget(oContainer) oWidget { setwindowtitle("Using Qt3D - Model Texture") resize(800,600) setLayout(oLayout) showMaximized() } exec() } 47.14. Model Texture 500
540.
Ring Documentation, Release1.16 47.15 Draw Office load "guilib.ring" new qApp { oView = new Qt3dwindow() oWidget = new QWidget() oContainer = oWidget.createWindowContainer(oView,oWidget,0) oRootEntity = new QEntity(oContainer) oInput = new QInputAspect(oRootEntity) oView.registerAspect(oInput) oCameraEntity = oView.Camera() oCameraEntity.lens().setPerspectiveProjection(45.0, 16.0/9.0, 0.1, 1000.0) oCameraEntity.setPosition(new QVector3D(0, 0, 20.0)) oCameraEntity.setUpVector(new QVector3D(0, 1, 0)) oCameraEntity.setViewCenter(new QVector3D(0, 0, 0)) oLightEntity = new QEntity(oRootEntity) oLight = new QPointLight(oLightEntity) oLight.setColor(new QColor() { setRGB(255,255,255,255) }) oLight.setIntensity(1) oLightEntity.addComponent(oLight) oLightTransform = new QTransform(oLightEntity) oLightTransform.setTranslation(oCameraEntity.position()) oLightEntity.addComponent(oLightTransform) (continues on next page) 47.15. Draw Office 501
541.
Ring Documentation, Release1.16 (continued from previous page) oCamController = new QFirstPersonCameraController(oRootEntity) oCamController.setCamera(oCameraEntity) oModel = new qmesh(oRootEntity) oModel.setsource( new qURL("file:///"+currentdir()+"/assets/model/Reception_Table.obj") ˓ →) oModelTransform = new QTransform(oModel) oModelTransform.setScale(1) oModelTransform.setTranslation(new QVector3D(0, -2.5, 16)) oModelMaterial = new QPhongMaterial(oModel) oModelMaterial.setDiffuse(new QColor() {setRGB(0,255,128,255)}) oModelEntity = new QEntity(oRootEntity) oModelEntity.addComponent(oModel) oModelEntity.addComponent(oModelmaterial) oModelEntity.addComponent(oModelTransform) oView.setRootEntity(oRootEntity) oLayout = new QVBoxLayout() oLayout.AddWidget(oContainer) oWidget { setwindowtitle("Using Qt3D - Model (Obj File) - Office") resize(800,600) setLayout(oLayout) showMaximized() } exec() } 47.15. Draw Office 502
542.
Ring Documentation, Release1.16 47.16 Many Objects load "guilib.ring" new qApp { oView = new Qt3dwindow() oWidget = new QWidget() oContainer = oWidget.createWindowContainer(oView,oWidget,0) oRootEntity = new QEntity(oContainer) oInput = new QInputAspect(oRootEntity) oView.registerAspect(oInput) oCameraEntity = oView.Camera() oCameraEntity.lens().setPerspectiveProjection(45.0, 16.0/9.0, 0.1, 1000.0) oCameraEntity.setPosition(new QVector3D(0, 0, 20.0)) oCameraEntity.setUpVector(new QVector3D(0, 1, 0)) oCameraEntity.setViewCenter(new QVector3D(0, 20, 0)) (continues on next page) 47.16. Many Objects 503
543.
Ring Documentation, Release1.16 (continued from previous page) oLightEntity = new QEntity(oRootEntity) oLight = new QPointLight(oLightEntity) oLight.setColor(new QColor() { setRGB(255,255,255,255) }) oLight.setIntensity(1) oLightEntity.addComponent(oLight) oLightTransform = new QTransform(oLightEntity) oLightTransform.setTranslation(oCameraEntity.position()) oLightEntity.addComponent(oLightTransform) oCamController = new QFirstPersonCameraController(oRootEntity) oCamController.setCamera(oCameraEntity) oModel = new qmesh(oRootEntity) oModel.setsource( new qURL("file:///"+currentdir()+"/assets/model/Robot.obj") ) oModelTransform = new QTransform(oModel) oModelTransform.setScale(0.2) oModelTransform.setTranslation(new QVector3D(0, 10, 10)) oModelMaterial = new QPhongMaterial(oModel) oModelMaterial.setDiffuse(new QColor() {setRGB(0,100,0,0)}) oModelEntity = new QEntity(oRootEntity) oModelEntity.addComponent(oModel) oLoader = new QTextureLoader(oModel); oModelMaterial = new QTextureMaterial(oModel) oLoader.setSource( new QUrl("file:///"+currentdir()+"/assets/texture/gold.jpg") ) oModelMaterial.setTexture(oLoader) oModelEntity.addComponent(oModelMaterial) oModelEntity.addComponent(oModelTransform) for n = 1 to 10 oTorus = new QTorusMesh(oRootEntity) oTorus.setRadius(1.0*n) oTorus.setMinorRadius(0.4*n) oTorus.setRings(100) oTorus.setSlices(20) oTorusTransform = new QTransform(null) oTorusTransform.setScale(2) oTorusTransform.setTranslation(new QVector3D(5.0*n, 4.0*n, 0.0)) oTorusMaterial = new QPhongMaterial(null); oTorusMaterial.setDiffuse(new QColor() {setRGB(200,100,100,100)}) oTorusEntity = new QEntity(oRootEntity) oTorusEntity.addComponent(oTorus) oLoader = new QTextureLoader(oTorus); oTorusMaterial = new QTextureMaterial(oTorus) (continues on next page) 47.16. Many Objects 504
544.
Ring Documentation, Release1.16 (continued from previous page) oLoader.setSource( new QUrl("file:///"+currentdir()+"/assets/texture/gold.jpg") ) oTorusMaterial.setTexture(oLoader) oTorusEntity.addComponent(oTorusMaterial) oTorusEntity.addComponent(oTorusTransform) next oView.setRootEntity(oRootEntity) oLayout = new QVBoxLayout() oLayout.AddWidget(oContainer) oWidget { setwindowtitle("Using Qt3D - Many Objects") resize(800,600) setLayout(oLayout) showMaximized() } exec() } 47.16. Many Objects 505
545.
Ring Documentation, Release1.16 47.17 Camera load "guilib.ring" new qApp { oView = new Qt3dwindow() oWidget = new QWidget() oContainer = oWidget.createWindowContainer(oView,oWidget,0) oRootEntity = new QEntity(oContainer) oInput = new QInputAspect(oRootEntity) oView.registerAspect(oInput) oCameraEntity = oView.Camera() oCameraEntity.lens().setPerspectiveProjection(45.0, 16.0/9.0, 0.1, 1000.0) oCameraEntity.setPosition(new QVector3D(0, 0, 20.0)) oCameraEntity.setUpVector(new QVector3D(0, 1, 0)) oCameraEntity.setViewCenter(new QVector3D(0, 20, 0)) oLightEntity = new QEntity(oRootEntity) oLight = new QPointLight(oLightEntity) oLight.setColor(new QColor() { setRGB(255,255,255,255) }) oLight.setIntensity(1) oLightEntity.addComponent(oLight) oLightTransform = new QTransform(oLightEntity) oLightTransform.setTranslation(oCameraEntity.position()) oLightEntity.addComponent(oLightTransform) oCamController = new QFirstPersonCameraController(oRootEntity) oCamController.setCamera(oCameraEntity) oModel = new qmesh(oRootEntity) oModel.setsource( new qURL("file:///"+currentdir()+"/assets/model/Robot.obj") ) oModelTransform = new QTransform(oModel) oModelTransform.setScale(0.2) oModelTransform.setTranslation(new QVector3D(0, 10, 10)) oModelMaterial = new QPhongMaterial(oModel) oModelMaterial.setDiffuse(new QColor() {setRGB(0,100,0,0)}) oModelEntity = new QEntity(oRootEntity) oModelEntity.addComponent(oModel) oLoader = new QTextureLoader(oModel); oModelMaterial = new QTextureMaterial(oModel) oLoader.setSource( new QUrl("file:///"+currentdir()+"/assets/texture/gold.jpg") ) oModelMaterial.setTexture(oLoader) oModelEntity.addComponent(oModelMaterial) (continues on next page) 47.17. Camera 506
546.
Ring Documentation, Release1.16 (continued from previous page) oModelEntity.addComponent(oModelTransform) for n = 1 to 10 oTorus = new QTorusMesh(oRootEntity) oTorus.setRadius(1.0*n) oTorus.setMinorRadius(0.4*n) oTorus.setRings(100) oTorus.setSlices(20) oTorusTransform = new QTransform(null) oTorusTransform.setScale(2) oTorusTransform.setTranslation(new QVector3D(5.0*n, 4.0*n, 0.0)) oTorusMaterial = new QPhongMaterial(null); oTorusMaterial.setDiffuse(new QColor() {setRGB(200,100,100,100)}) oTorusEntity = new QEntity(oRootEntity) oTorusEntity.addComponent(oTorus) oLoader = new QTextureLoader(oTorus); oTorusMaterial = new QTextureMaterial(oTorus) oLoader.setSource( new QUrl("file:///"+currentdir()+"/assets/texture/gold.jpg") ) oTorusMaterial.setTexture(oLoader) oTorusEntity.addComponent(oTorusMaterial) oTorusEntity.addComponent(oTorusTransform) next oView.setRootEntity(oRootEntity) btn1 = new qPushButton(oWidget) { setText("Move the Camera and the Robot") setClickEvent("pMove()") } oLayout = new QVBoxLayout() oLayout.AddWidget(oContainer) oLayout.AddWidget(btn1) oWidget { setwindowtitle("Using Qt3D - Camera") resize(800,600) setLayout(oLayout) showMaximized() } exec() } func pMove oCameraEntity.setPosition(new QVector3D(0, 0, 20.0)) oCameraEntity.setUpVector(new QVector3D(0, 1, 0)) oCameraEntity.setViewCenter(new QVector3D(20, 15, 20)) (continues on next page) 47.17. Camera 507
547.
Ring Documentation, Release1.16 (continued from previous page) oModelTransform.setTranslation(new QVector3D(20, 15, 20)) oQ = new QQuaternion(0,0,0,0) oModelTransform.setRotation(oQ.fromAxisAndAngle(new QVector3D(1, 1, 0), 270)) 47.18 Scence load "guilib.ring" new qApp { oWidget = new QWidget() oView = new Qt3DWindow() oView.defaultFrameGraph().setClearColor(new QColor() {setRGB(0,0,0,255)}) oContainer = oWidget.createWindowContainer(oView,oWidget,0) oRootEntity = new QEntity(oContainer) oInput = new QInputAspect(oRootEntity) oView.registerAspect(oInput) oCameraEntity = oView.Camera() oCameraEntity.lens().setPerspectiveProjection(45.0, 16.0/9.0, 0.1, 1000) oCameraEntity.setPosition(new QVector3D(-13.34, -6.43, 16.47)) oCameraEntity.setUpVector(new QVector3D(0.02, 0, 1)) oCameraEntity.setViewCenter(new QVector3D(-13.34, 17.05, 15.42)) (continues on next page) 47.18. Scence 508
548.
Ring Documentation, Release1.16 (continued from previous page) oCameraController = new QFirstPersonCameraController(oRootEntity) oCameraController.setCamera(oCameraEntity) oCameraController.setEnabled(False) oLongRoomEntity = new QEntity(oRootEntity) oLongRoomModel = new QMesh(oLongRoomEntity) oLongRoomModel.setSource( new qURL("file:///"+CurrentDir()+"/assets/model/Long_Room.obj") ) oLongRoomTransform = new QTransform(oLongRoomEntity) oLongRoomTransform.setScale(1) oLongRoomTransform.setTranslation(new QVector3D(5, 0, 15)) oLongRoomLoader = new QTextureLoader(oLongRoomModel) oLongRoomMaterial = new QTextureMaterial(oLongRoomModel) oLongRoomLoader.setSource( new QUrl("file:///"+currentdir()+"/assets/texture/croc.jpg") ) oLongRoomMaterial.setTexture(oLongRoomLoader) oLongRoomEntity.addComponent(oLongRoomModel) oLongRoomEntity.addComponent(oLongRoomMaterial) oLongRoomEntity.addComponent(oLongRoomTransform) oTableEntity = new QEntity(oRootEntity) oTableModel = new QMesh(oTableEntity) oTableModel.setSource( new qURL("file:///"+CurrentDir()+"/assets/model/Reception_Table.obj") ˓ →) oTableTransform = new QTransform(oTableEntity) oTableTransform.setScale(0.3) oTableTransform.setTranslation(new QVector3D(5, 0, 15)) oQ = new QQuaternion(0,0,0,0) oTableTransform.setRotation(oQ.fromAxisAndAngle(new QVector3D(0, 1, 1), -180)) oTableModelMaterial = new QPhongMaterial(oTableEntity) oTableModelMaterial.setDiffuse(new QColor() {setRGB(255,255,255,255)}) oTableEntity.addComponent(oTableModel) oTableEntity.addComponent(oTableModelmaterial) oTableEntity.addComponent(oTableTransform) oFirstLightEntity = new QEntity(oRootEntity) oFirstLight = new QPointLight(oFirstLightEntity) oFirstLight.setColor(new qColor() { setRGB(128,128,128,128) }) oFirstLight.setIntensity(1) oFirstLightTransform = new QTransform(oFirstLightEntity) oFirstLightTransform.setTranslation(new QVector3D(5, 0, 20)) oFirstLightEntity.addComponent(oFirstLight) oFirstLightEntity.addComponent(oFirstLightTransform) (continues on next page) 47.18. Scence 509
549.
Ring Documentation, Release1.16 (continued from previous page) aCats = list(5) for n = 1 to 5 v = n * 0.1 aCats[n] = [] aCats[n][:oCatModelEntity] = new QEntity(oRootEntity) aCats[n][:oCatModel] = new QMesh(aCats[n][:oCatModelEntity]) aCats[n][:oCatModel].setSource( new qURL("file:///"+CurrentDir()+"/assets/model/Lucky_Cat.obj") ) aCats[n][:oCatModelMaterial] = new QPhongMaterial(aCats[n][:oCatModel]) aCats[n][:oCatModelMaterial].setDiffuse( new QColor() {setRGB(255,255,255,255)}) aCats[n][:oCatModelTransform] = new QTransform(aCats[n][:oCatModelEntity]) aCats[n][:oCatModelTransform].setScale(0.01) aCats[n][:oCatModelTransform].setTranslation( new QVector3D(-5*(v+v), 1, 15.2)) oQ = new QQuaternion(0,0,0,0) aCats[n][:oCatModelTransform].setRotation( oQ.fromAxisAndAngle( new QVector3D(0, 1, 1), 180)) aCats[n][:oCatModelEntity].addComponent(aCats[n][:oCatModel]) aCats[n][:oCatModelEntity].addComponent(aCats[n][:oCatModelmaterial]) aCats[n][:oCatModelEntity].addComponent(aCats[n][:oCatModelTransform]) next oSecondLightEntity = new QEntity(oRootEntity) oSecondLight = new QPointLight(oSecondLightEntity) oSecondLight.setColor(new qColor() { setRGB(255,255,255,255) }) oSecondLight.setIntensity(1) oSecondLightTransform = new QTransform(oSecondLightEntity) oSecondLightTransform.setTranslation(new QVector3D(-5, 1, 15.5)) oSecondLightEntity.addComponent(oSecondLight) oSecondLightEntity.addComponent(oSecondLightTransform) oRobotEntity = new QEntity(oRootEntity) oRobotModel = new QMesh(oRobotEntity) oRobotModel.setSource( new qURL("file:///"+CurrentDir()+"/assets/model/Fat_Robot.obj") ) oRobotTransform = new QTransform(oRobotEntity) oRobotTransform.setScale(0.006) robotX = -15 robotY = -2 robotZ = 15 oRobotTransform.setTranslation(new QVector3D(-15, -2, 15)) oQ = new QQuaternion(0,0,0,0) oRobotTransform.setRotation( oQ.fromAxisAndAngle(new QVector3D(0, 1, 1), 170)) oRobotMaterial = new QPhongMaterial(oRobotEntity) oRobotMaterial.setDiffuse(new QColor() {setRGB(128,128,128,255)}) oRobotEntity.addComponent(oRobotModel) (continues on next page) 47.18. Scence 510
550.
Ring Documentation, Release1.16 (continued from previous page) oRobotEntity.addComponent(oRobotTransform) oRobotEntity.addComponent(oRobotMaterial) oView.setRootEntity(oRootEntity) oWidget { setwindowtitle("Using Qt3D - Scene") showfullscreen() } oContainer.resize(oWidget.width(),oWidget.height()) oFilter = new QAllEvents(oView) oFilter.setKeyPressEvent("pKeyPress()") oView.installeventfilter(oFilter) oContainer.setfocus(0) exec() } func pKeyPress nKey = oFilter.getKeyCode() nSpeed = 0.1 cX = oCameraEntity.position().x() CY = oCameraEntity.position().y() cZ = oCameraEntity.position().z() cVCx = oCameraEntity.viewCenter().x() cVCy = oCameraEntity.viewCenter().y() cVCz = oCameraEntity.viewCenter().z() switch nKey on Qt_Key_Right if cX < 4.8 robotX+= nSpeed oCameraEntity.setPosition( new QVector3D(cX+0.1, cY, cZ)) oCameraEntity.setViewCenter( new QVector3D(cVCx+nSpeed, cVCy, cVCz)) oRobotTransform.setRotation( oQ.fromAxisAndAngle(new QVector3D(0, 1, 1), ˓ →170)) ok on Qt_Key_Left if cX > - 13.8 robotX-= nSpeed oCameraEntity.setPosition( new QVector3D(cX-0.1, cY, cZ)) oCameraEntity.setViewCenter( new QVector3D(cVCx-nSpeed, cVCy, cVCz)) oRobotTransform.setRotation( oQ.fromAxisAndAngle(new QVector3D(0, 1, 1), 160)) ok on Qt_Key_Down if robotY > -3.5 robotY-= nSpeed (continues on next page) 47.18. Scence 511
551.
Ring Documentation, Release1.16 (continued from previous page) oCameraEntity.setPosition( new QVector3D(cX, cY, cZ)) oRobotTransform.setRotation( oQ.fromAxisAndAngle(new QVector3D(0, 1, 1), 190)) ok on Qt_Key_Up if robotY < 2 robotY+= nSpeed oCameraEntity.setPosition( new QVector3D(cX, cY, cZ)) oRobotTransform.setRotation( oQ.fromAxisAndAngle(new QVector3D(0, 1, 1), 180)) ok on Qt_Key_Escape oWidget.close() off oRobotTransform.setTranslation(new QVector3D(robotX, robotY, robotZ)) 47.18. Scence 512
552.
CHAPTER FORTYEIGHT OBJECTS LIBRARY FORRINGQT APPLICATION In this chapter we will learn about the objects library and using it in GUI applications. Instead of using global variables for windows objects and connecting events to objects using the object name, the Objects Library will manage a list of the GUI objects and will provide a more natural API to quickly create one or many windows from the same class. Also the Objects Library provide a way to quickly set methods to be executed when an event is fired. Also the library provide a natural interface to quickly use the parent or the caller windows from the child or sub windows and the other way around. The Objects Library is designed to be used with the MVC Design Pattern. The Objects Library uses reflection and meta-programming to add new methods to Controller classes to provide an easy way for communication between these classes. The Objects Library is called automatically by the GUILib Also we can call it alone by using the next command load "objectslib.ring" The ObjectsLib provide functions like openObject(), lastObject() and a class called ObjectsParent The GUILib provide a new specific API for GUI applications like openWindow(), lastWindow(), etc. 48.1 Library Usage with GUI Applications • Use the openWindow(cWindowControllerClassName) function to open new Windows • Create at least Two Classes for each window, The Controller Class and the View Class • Create each controller class from the WindowsControllerParent Class • Create each view class from the WindowsViewParent Class • Use the lastWindow() function to get the object of the last window created (The Controller object). • When you call a sub window, use the SetParentObject() method and pass the self object. • In the View Class, To determine the event method use the Method(cMethodName) function. • The Method(cMethodName) function determine the method in the controller class that will be executed. • Each controller class contains by default the CloseAction() method that you can call to close the window. • You don’t need to call the Show() Method for each window, When you use openWindow() It will be called. • In the view class, Define the GUI window object as an attribute called win. 513
553.
Ring Documentation, Release1.16 • You can use openWindowNoShow() to avoid displaying the window. • You can use openWindowAndLink() to quickly get methods to access the windows. 48.2 Example In the next example we will create two types of windows. • Main Window contains a button. When the user click on the button a sub window will be opened. • The User Can click on the button many times to open many sub windows. • Each Sub Window contains Two buttons. • The first button in the sub window change the Main and the Sub Windows Titles. • The second button in the sub window close the Sub Window. load "guilib.ring" new qApp { openWindow( :MainWindowController ) exec() } class MainWindowController from WindowsControllerParent oView = new MainWindowView func SubWindowAction openWindow( :SubWindowController ) lastWindow().SetParentObject(self) class MainWindowView from WindowsViewParent win = new qWidget() { SetWindowTitle("Main Window") btnSub = new qPushButton(win) { setText("Sub Window") setClickEvent( Method( :SubWindowAction ) ) } resize(400,400) } class SubWindowController from WindowsControllerParent oView = new SubWindowView func SetMainWindowTitleAction Parent().oView.win.SetWindowTitle("Message from the Sub Window") oView.win.SetWindowTitle("Click Event Done!") class SubWindowView from WindowsViewParent win = new qWidget() { SetWindowTitle("Sub Window") btnMsg = new qPushButton(win) { setText("Set Main Window Title") setClickEvent( Method( :SetMainWindowTitleAction ) ) } btnClose = new qPushButton(win) { Move(200,0) setText("Close") setClickEvent( Method( :CloseAction ) ) (continues on next page) 48.2. Example 514
554.
Ring Documentation, Release1.16 (continued from previous page) } resize(400,400) } The next screen shot after creating three sub windows. The next screen shot after clicking on the button in each sub window. 48.2. Example 515
555.
Ring Documentation, Release1.16 48.3 openWindowAndLink() Function We can use the openWindowAndLink() function to connect between the application windows, pass messages (call methods) between the objects. This function uses Meta-programming to define dynamic methods in the Caller Class to use the dynamic objects of other windows that we create. Example : (Uses the Form Designer) First Window (1) https://github.com/ring-lang/ring/blob/master/samples/UsingFormDesigner/twowindowspart5/ firstwindowView.ring (2) https://github.com/ring-lang/ring/blob/master/samples/UsingFormDesigner/twowindowspart5/ firstwindowController.ring Second Window 48.3. openWindowAndLink() Function 516
556.
Ring Documentation, Release1.16 (1) https://github.com/ring-lang/ring/blob/master/samples/UsingFormDesigner/twowindowspart5/ secondwindowView.ring (2) https://github.com/ring-lang/ring/blob/master/samples/UsingFormDesigner/twowindowspart5/ secondwindowController.ring In the next code for example (from FirstWindowController.ring) The openWindowAndLink() will create an object from the SecondWindowController Class Then will add the SecondWindow() and IsSecondWindow() Methods to the FirstWindowController Class Also will add the FirstWindow() and IsFirstWindow() Methods to the SecondWindowController Class So the SendMessage() method in FirstWindowController class can use the SecondWindow() method to access the object. This is more simple than using lastWindow(), Parent() and SetParentObject() methods. class firstwindowController from windowsControllerParent oView = new firstwindowView func OpenSecondWindow openWindowAndLink(:SecondWindowController,self) func SendMessage if IsSecondWindow() SecondWindow().setMessage("Message from the first window") ok func setMessage cMessage oView.Label1.setText(cMessage) 48.4 openWindowInPackages() Function The openWindowInPackages() function is the same as openWindow() but takes an extra list that determine the pack- ages to import before opening the window. Syntax: openWindowInPackages(cClassName,aPackagesList) Example: The next example from the Form Designer source code, Open the Window Flags window using the openWindowIn- Packages() function. We determine the class name “WindowFlagsController” and the packages name. The Window Flags window uses the FormDesigner and System.GUI packages. openWindowInPackages(:WindowFlagsController,[ "formdesigner", "System.GUI" ]) 48.4. openWindowInPackages() Function 517
557.
Ring Documentation, Release1.16 48.5 Objects Library Source Code The library source code is very simple, You can check the source code files The source code for the Objects Library (can be used without GUILib) • https://github.com/ring-lang/ring/blob/master/libraries/objectslib/objects.ring • https://github.com/ring-lang/ring/blob/master/libraries/objectslib/objectslib.ring The source code for the MVC classes in GUILib • https://github.com/ring-lang/ring/blob/master/libraries/guilib/mvc/controllerparent.ring • https://github.com/ring-lang/ring/blob/master/libraries/guilib/mvc/viewparent.ring 48.5. Objects Library Source Code 518
558.
CHAPTER FORTYNINE MULTI-LANGUAGE APPLICATIONS There aremany ways to create multi-language Ring application! In this chapter we will learn about using the String2Constant tool 49.1 Using String2Constant Starting from Ring 1.8 we have the String2Constant application You will find this tool in the ring/tools/string2constant folder Using this tool we can convert the source code to be based on constants instead of string literals Then we can store constants in separate source code files that we can translate to different languages Where we can have special file for each language, like (English.ring, Arabic.ring and so on) Using this simple tool, the Form Designer is translated to Arabic language too just as an example. 519
559.
Ring Documentation, Release1.16 49.2 Form Designer Translation You will find the form designer application in the ring/applications/formdesigner folder The files used for translation are stored in the ring/applications/formdesigner/translation folder You will find two files • Arabic.ring • English.ring You can check these files to get an idea about constants definition. The next section from the English.ring file 49.2. Form Designer Translation 520
560.
Ring Documentation, Release1.16 T_LANGUAGE = "english" T_LAYOUTDIRECTION = 0 # Left to Right T_FORMDESIGNER_FORMDESIGNER = "Form Designer" T_FORMDESIGNER_FORMTITLE = "Form1" T_FORMDESIGNER_FILE = "File" T_FORMDESIGNER_NEW = "New" T_FORMDESIGNER_OPEN = "Open" T_FORMDESIGNER_SAVE = "Save" T_FORMDESIGNER_SAVEAS = "Save As" T_FORMDESIGNER_CLOSE = "Close" The form designer source code files will use these constants instead of typing the string literals the next section from the formdesigner/mainwindow/formdesignerview.ring # Create the Main Window and use the Mdi Area win = new qMainwindow() { setWindowTitle(T_FORMDESIGNER_FORMDESIGNER) # "Form Designer" setcentralWidget(this.oArea) setLayoutDirection(T_LAYOUTDIRECTION) } • Using comments we can write the string literal to get more readable code. • Using setLayoutDirection() method we can set the window direction to be Right To Left. • Using the Load command, We can determine which translation file to use. 49.3 Forms Translation After creating the form using the Form Designer, the View class will be generated. We don’t modify the view class, We just add the translation through the Controller class. For example, we have the form file : ring/formdesigner/selobjects/selobjects.rform 49.3. Forms Translation 521
561.
Ring Documentation, Release1.16 And we add the translation through the Controller class using the next code And we define the constants in English.ring and Arabic.ring class selobjectsController from windowsControllerParent oView = new selobjectsView { ListObjects.setselectionmode(QAbstractItemView_MultiSelection) win.setwindowmodality(2) # Translation win.setWindowTitle(T_FORMDESIGNER_SELOBJECTS_TITLE) win.setLayoutDirection(T_LAYOUTDIRECTION) labelobjects.setText(T_FORMDESIGNER_SELOBJECTS_OBJECTS) btnSelect.setText(T_FORMDESIGNER_SELOBJECTS_SELECT) btnClose.setText(T_FORMDESIGNER_SELOBJECTS_CLOSE) } 49.3. Forms Translation 522
562.
CHAPTER FIFTY BUILDING RINGQT APPLICATIONSFOR MOBILE In this chapter we will learn about Building RingQt Applications for Mobile. 50.1 Download Requirements Check the next link : http://doc.qt.io/qt-5/androidgs.html Download • The Android SDK Tools https://developer.android.com/sdk/index.html • The Android NDK (Tested using android-ndk-r21) http://developer.android.com/tools/sdk/ndk/index.html • Java SE Development Kit (JDK) v6 or later https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 50.2 Update the Android SDK Update the Android SDK to get the API and tools packages required for development Tested using Android 4.4.2 (API 19) • In Windows - Define the next Environment Variables based on your system. (1) JAVA_HOME For Example : C:Program Files (x86)Javajdk1.8.0_05 (2) ANDROID_HOME For Example : C:JavaAndroidAndroidSDK 523
563.
Ring Documentation, Release1.16 50.3 Install Qt for Android • You can install Qt for Android from the next link https://download.qt.io/archive/qt/5.12/5.12.6/ • Run Qt Creator, Select Tools > Options > Android to add the Android NDK and SDK paths. http://doc.qt.io/qtcreator/creator-developing-android.html 50.4 Using Ring2EXE We can use Ring2EXE to quickly prepare Qt project for our application Example: ring2exe myapp.ring -dist -mobileqt Note: We can use the Distribute Menu in Ring Notepad Tip: The option ( Prepare Qt project for Mobile devices ) in the Distribute Menu 50.5 The Qt project for your Ring application After using Ring2EXE or the Distribute Menu in Ring Notepad • Using the Qt Creator Open the generated Qt project Folder : target/mobile/qtproject Project file : project.pro • Using Qt Creator, You will find the compiled Ring application in the resources (YourAppName.ringo) This file (Ring Object File) is generated by the Ring compiler using ring YourAppName.ring -go -norun • You can build your application using Qt Creator (1) You can add your application images to the resources Or You can use any text editor (Notepad) and modify : project.qrc (2) To find images from your Ring application, You need to use the file name in resources Example if isandroid() mypic = new QPixmap(":/cards.jpg") else mypic = new QPixmap("cards.jpg") ok 50.3. Install Qt for Android 524
564.
Ring Documentation, Release1.16 50.6 Comments about developing for Android using RingQt (1) The main project file is main.cpp This file load Ring Compiler/Virtual Machine and RingQt Then get the Ring Object File during the runtime from the resources Then run the Ring Object File (ringapp.ringo) using the Ring VM Through main.cpp you can extract more files from the resources to temp. folder once you add them (create projects with many files). (2) The next functions are missing from this Ring edition • Database (ODBC, SQLite & MySQL) • Security and Internet functions (LibCurl & OpenSSL) • RingAllegro (Allegro Library) • RingLibSDL (LibSDL Library) Just use Qt Classes through RingQt. For database access use the QSqlDatabase Class Note: All of the missing libraries ((LibCurl, OpenSSL & Allegro) can be compiled for Android, but they are not included in this Qt project. (3) use if isandroid() when you want to modify the code just for android Example: if isandroid() // Android code else // other platforms ok (4) Sometimes you will find that the button text/image is repeated in drawing ! it’s Qt problem that you can avoid using the next code. if isandroid() setStyleSheet(" border-style: outset; border-width: 2px; border-radius: 4px; border-color: black; padding: 6px;") ok (5) Always use Layouts instead of manual setting of controls position and size. This is the best way to get the expected user interface to avoid problems like (controls with small/extra size) (6) When you deal with Qt Classes you can determine the images from resources (you don’t need to copy them using main.cpp) Example: 50.6. Comments about developing for Android using RingQt 525
565.
Ring Documentation, Release1.16 if isandroid() mypic = new QPixmap(":/cards.jpg") else mypic = new QPixmap("cards.jpg") ok Now RingQt comes with the AppFile() function to determine the file name Example: mypic = new QPixmap(AppFile("cards.jpg")) # Desktop or Android (7) When you update your project code, You don’t have to use Ring2EXE to generate the Qt project again Just use the Distribute Menu in Ring Notepad and select (Generate Ring Object File) Then copy the YourAppName.ringo file to target/mobile/qtproject folder and accept replacing files. (8) If your application folder contains a Qt resource file (project.qrc) Then when you use Ring2EXE or Ring Notepad (Distribute - Prepare Qt project for Mobile devices) the resource file will be used See ring/applications/cards game as an example. 50.6. Comments about developing for Android using RingQt 526
566.
CHAPTER FIFTYONE BUILDING RINGQT APPLICATIONSFOR WEBASSEMBLY In this chapter we will learn about Building RingQt Applications for WebAssembly. 51.1 Download Requirements Check the next link : https://doc.qt.io/qt-5/wasm.html Tested using • Qt (5.15.0) : https://www.qt.io/blog/qt-5.15-released • Emscripten (1.39.7) : https://emscripten.org/docs/getting_started/index.html emsdk install sdk-fastcomp-1.39.7-64bit emsdk activate sdk-fastcomp-1.39.7-64bit Check Emscripten installation em++ --version Output emcc (Emscripten gcc/clang-like replacement) 1.39.7 (commit 24d88487f47629fac9d4acd231497a3a412bdee8) Copyright (C) 2014 the Emscripten authors (see AUTHORS.txt) This is free and open source software under the MIT license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 51.2 Using Ring2EXE We can use Ring2EXE to quickly prepare Qt project for our application Example: ring2exe myapp.ring -dist -webassemblyqt Note: We can use the Distribute Menu in Ring Notepad 527
567.
Ring Documentation, Release1.16 Tip: The option ( Prepare Qt project for WebAssembly ) in the Distribute Menu 51.3 The Qt project for your Ring application After using Ring2EXE or the Distribute Menu in Ring Notepad • Using the Qt Creator Open the generated Qt project Folder : target/webassembly/qtproject Project file : project.pro • Using Qt Creator, You will find the compiled Ring application in the resources (YourAppName.ringo) This file (Ring Object File) is generated by the Ring compiler using ring YourAppName.ring -go -norun • You can build your application using Qt Creator (1) You can add your application images to the resources Or You can use any text editor (Notepad) and modify : project.qrc (2) To find images from your Ring application, You need to use the file name in resources Example if isWebAssembly() mypic = new QPixmap(":/cards.jpg") else mypic = new QPixmap("cards.jpg") ok 51.4 Comments about developing for WebAssembly using RingQt (1) The main project file is main.cpp This file load Ring Compiler/Virtual Machine and RingQt Then get the Ring Object File during the runtime from the resources Then run the Ring Object File (ringapp.ringo) using the Ring VM Through main.cpp you can extract more files from the resources to temp. folder once you add them (create projects with many files). (2) use if isWebAssembly() when you want to modify the code just for WebAssembly Example: if isWebAssembly() // WebAssembly code else // other platforms ok 51.3. The Qt project for your Ring application 528
568.
Ring Documentation, Release1.16 (3) When you deal with Qt Classes you can determine the images from resources (you don’t need to copy them using main.cpp) Example: if isWebAssembly() mypic = new QPixmap(":/cards.jpg") else mypic = new QPixmap("cards.jpg") ok Now RingQt comes with the AppFile() function to determine the file name Example: mypic = new QPixmap(AppFile("cards.jpg")) # Desktop, Android or WebAssembly (4) When you update your project code, You don’t have to use Ring2EXE to generate the Qt project again Just use the Distribute Menu in Ring Notepad and select (Generate Ring Object File) Then copy the YourAppName.ringo file to target/webassembly/qtproject folder and accept replacing files. (5) If your application folder contains a Qt resource file (project.qrc) Then when you use Ring2EXE or Ring Notepad (Distribute - Prepare Qt project for WebAssembly) the resource file will be used See ring/applications/cards game as an example. (6) Use stdlibcore.ring instead of stdlib.ring when using StdLib functions (7) Use ClocksPerSecond() function instead of typing the value (1000) (8) Nested events loops are not supported, use events for dialogs instead of calling the exec() method (9) Using Sleep() or ProcessEvents() doesn’t provide the expected results, use Qt Timers. (10) We don’t have a direct access to the File System because the applications are executed in a secure environment Tip: We can use special functions for Uploading/Downloading files (See FileContent sample) 51.5 Dialogs See the folder: ring/samples/UsingQtWASM Folders: • ColorDialog • FontDialog • FileDialog • FileContent 51.5. Dialogs 529
569.
Ring Documentation, Release1.16 51.6 Online Applications • Hello World : https://ring-lang.github.io/web/helloworld/project.html • Matching Game : https://ring-lang.github.io/web/matching/project.html • Pairs Game : https://ring-lang.github.io/web/pairs/project.html • Othello Game : https://ring-lang.github.io/web/othello/project.html • Game of Life : https://ring-lang.github.io/web/gameoflife/project.html • Form Designer : https://ring-lang.github.io/web/formdesigner/project.html 51.6. Online Applications 530
570.
CHAPTER FIFTYTWO WEB DEVELOPMENT (CGILIBRARY) In this chapter we will learn about developing Web applications using a CGI Library written in the Ring language. 52.1 Configure the Apache web server In this section we will learn about using Ring with the Apache HTTP Server. We can also use Ring with any web server that supports CGI. Note: If you are developing your application using Ring Notepad then there’s no need to configure Apache manually. 52.1.1 Using XAMPP Apache web server Here we will use the XAMPP application that has Apache web server already been included. You can download XAMPP package from this link XAMPP : https://www.apachefriends.org/download.html Install then open the configuration file from the XAMPP application or search for it in the following locations based on your operating system. For Windows: xamppapacheconfhttpd.conf For Linux: /opt/lampp/etc/httpd.conf For macOS: /Applications/XAMPP/xamppfiles/etc/httpd.conf Search for the next line and make sure that it’s not commented LoadModule cgi_module modules/mod_cgi.so Search for : AddHandler cgi-script Then add “.ring” to the supported cgi extensions Example 531
571.
Ring Documentation, Release1.16 AddHandler cgi-script .cgi .ring Example AddHandler cgi-script .cgi .pl .asp .ring Restart/Start the server using XAMPP “Manage Servers” or “Services” section Create your web applications in a directory supported by the web server. For Windows: xampphtdocsmywebapplicationfolder For Linux: /opt/lampp/htdocs/mywebapplicationfolder For macOS: Open XAMPP application then go to "Volumes" section Mount the "/opt/lampp" volume Open Finder then you will find it mounted as an IP address under "Locations" on the ˓ →left menu 52.2 Setting the shebang line For Ring files to run properly under CGI we need to set the shebang line to locate the executable file of Ring. So, Inside the source code file (*.ring), Add next line as the very first line in the file: For Windows: #!ring -cgi For Linux: #!/usr/bin/ring -cgi For macOS: #!/usr/local/bin/ring -cgi Note: Change the previous line based on the path to ring executable in your machine 52.2. Setting the shebang line 532
572.
Ring Documentation, Release1.16 52.3 Grant Ring files execution permission In Linux and Mac operating systems ring files cannot be run properly using CGI until we grant them executable permission. You can do that using the properties section of your preferred File manager or you can do it using Terminal as follow: sudo chmod +x ringAppFile.ring Note: If you are developing your application using Ring Notepad then this step will be done automatically. 52.4 Ring CGI Hello World Program The next program is the Hello World program For Windows: #!ring -cgi See "content-type: text/html" +nl+nl+ "Hello World!" + nl For Linux: #!/usr/bin/ring -cgi See "content-type: text/html" +nl+nl+ "Hello World!" + nl For macOS: #!/usr/local/bin/ring -cgi See "content-type: text/html" +nl+nl+ "Hello World!" + nl 52.5 Hello World Program using the Web Library We can use the web library to write CGI Web applications quickly Example (1) : #!ring -cgi Load "weblib.ring" Import System.Web New Page { Text("Hello World!") } 52.3. Grant Ring files execution permission 533
573.
Ring Documentation, Release1.16 Example (2) : #!ring -cgi Load "weblib.ring" Import System.Web WebPage() { Text("Hello World!") } Tip: the difference between ex. 1 and ex. 2 is using WebPage() function to return the page object instead of creating the object using new statement. 52.6 Web Library Features The next features are provided by the Web library to quickly create web applications. • Generate HTML pages using functions • Generate HTML pages using objects • HTTP Get • HTTP Post • Files Upload • URL Encode • Templates • CRUD MVC Sample • Users Logic & Registration Sample 52.7 HTTP Get Example The Page User Interface #!ring -cgi Load "weblib.ring" Import System.Web New Page { Title = "Test HTTP Get" divstart([ :style = StyleSizeFull() ] ) boxstart() text( "Test HTTP GET" ) newline() boxend() divstart([ :style = Styledivcenter("600px","550px") + StyleGradient(21) ]) (continues on next page) 52.6. Web Library Features 534
Ring Documentation, Release1.16 The Response #!ring -cgi Load "weblib.ring" Import System.Web New Page { divstart([ :style = styledivcenter("800px","500px") ]) boxstart() text ( "HTTP GET Response" ) newline() boxend() (continues on next page) 52.7. HTTP Get Example 537
577.
Ring Documentation, Release1.16 (continued from previous page) divstart([ :style = stylefloatleft()+stylewidth("10%")+ stylecolor("black")+stylegradient(58) ]) newline() text ( "Name : " ) newline() newline() text ( "Address : " ) newline() newline() text ( "Phone : " ) newline() newline() text ( "Age : " ) newline() newline() text ( "City : " ) newline() newline() text ( "Country : " ) newline() newline() text ( "Note : " ) newline() newline() divend() divstart([ :style = stylefloatleft()+stylewidth("90%")+ stylecolor("black")+stylegradient(47) ]) divstart([ :style = stylefloatleft() + stylewidth("1%") ]) newline() divend() divstart([ :style = stylefloatleft() + stylewidth("95%") ]) newline() text ( aPageVars["Name"] ) newline() newline() text ( aPageVars["Address"] ) newline() newline() text ( aPageVars["Phone"] ) newline() newline() text ( aPageVars["Age"] ) newline() newline() text ( aPageVars["City"] ) newline() newline() text (aPageVars["Country"] ) newline() newline() text ( aPageVars["Notes"] ) newline() newline() divend() divend() divend() } Screen Shot: 52.7. HTTP Get Example 538
Ring Documentation, Release1.16 52.12 Templates Using Templates we can write Ring code inside HTML files Syntax: <%= Ring Expression %> <% Ring Statements %> The HTML Code <h1>Listing Numbers</h1> <table> <tr> <th> <%= myheader.cColumn1 %> </th> <th> <%= myheader.cColumn2 %> </th> <th></th> <th></th> <th></th> </tr> <% for x in aNumbers %> <tr> <td> <%= x.nValue %> </td> <td> <%= x.nSquare %> </td> </tr> <% next %> </table> The Ring Code #!ring -cgi Load "weblib.ring" Import System.Web (continues on next page) 52.12. Templates 547
587.
Ring Documentation, Release1.16 (continued from previous page) New NumbersController { start() } Class NumbersController MyHeader aNumbers Func Start MyHeader = New Header { cColumn1 = "Number" cColumn2 = "Square" } aNumbers = list(20) for x = 1 to len(aNumbers) aNumbers[x] = new number { nValue = x nSquare = x*x } next cTemp = Template("mynumbers.html",self) New Page { boxstart() text( "Test Templates" ) newline() boxend() html(cTemp) } Class Header cColumn1 cColumn2 Class Number nValue nSquare Screen Shot: 52.12. Templates 548
Ring Documentation, Release1.16 52.13 HTML Special Characters The text() function display HTML special characters. If you want to write html code, use the html() function. #!ring -cgi Load "weblib.ring" Import System.Web New Page { boxstart() text("HTML Special Characters") newline() boxend() text(' <html> <body> <p> "hello world" </p> </body> </html> ') } Screen Shot: 52.14 Hash Functions The Page User Interface #!ring -cgi Load "weblib.ring" Import System.Web New Page { boxstart() text( "Hash Test") newline() boxend() divstart([ :style = StyleFloatLeft() + StyleWidth("100px") ]) (continues on next page) 52.13. HTML Special Characters 550
Ring Documentation, Release1.16 52.16 HTML Lists The next example print a list contains numbers from 1 to 10 Then print a list from Ring List. Finally we have a list of buttons and when we press on a button we get a message contains the clicked button number. To start the list we uses the ulstart() function. To end the list we uses the ulend() function. We uses listart() and liend() to determine the list item. #!ring -cgi Load "weblib.ring" Import System.Web Func Main New Page { ulstart([]) for x = 1 to 10 listart([]) text(x) liend() next ulend() list2ul(["one","two","three","four","five"]) ulstart([]) for x = 1 to 10 (continues on next page) 52.16. HTML Lists 553
593.
Ring Documentation, Release1.16 (continued from previous page) listart([]) cFuncName = "btn"+x+"()" button([ :onclick = cFuncName , :value = x]) script(scriptfuncalert(cFuncName,string(x))) liend() next ulend() } Screen Shot: 52.16. HTML Lists 554
Ring Documentation, Release1.16 52.17 HTML Tables In this example we will learn how to generate HTML tables using the tablestart(), tableend(), rowstart(), rowend() ,headerstart(), headerend(), cellstart() and cellend() functions. #!ring -cgi Load "weblib.ring" Import System.Web Func Main New Page { divstart([ :style = styledivcenter("400px","500px") ] ) style(styletable() + styletablerows("t01")) tablestart([ :id = :t01 , :style = stylewidth("100%") ]) rowstart([]) headerstart([]) text("Number") headerend() headerstart([]) text("square") headerend() rowend() for x = 1 to 10 rowstart([]) cellstart([]) text(x) cellend() cellstart([]) text(x*x) cellend() rowend() next tableend() divend() } Screen Shot: 52.17. HTML Tables 556
596.
Ring Documentation, Release1.16 52.18 Gradient In this example we will learn how to use the StyleGradient() function. The function takes the style number as input (range from 1 to 60). #!ring -cgi Load "weblib.ring" Import System.Web Func Main New Page { boxstart() text("StyleGradient() Function") boxend() for x = 1 to 60 divstart([ :id = x , :align = "center" , :style = stylefloatleft() + stylesize(string(100/60*6)+"%","50px") + stylegradient(x) ]) h3(x) divend() next } Screen Shot: 52.18. Gradient 557
597.
Ring Documentation, Release1.16 52.19 Generating Pages using Objects Instead of using functions/methods to generate HTML pages, we can use an object for each element in the page. This choice means more beautiful code but slower. The fastest method is to print HTML code directly, then using functions then using templates then using objects (slower). #!ring -cgi Load "weblib.ring" Import System.Web Func Main WebPage() { Title = "Using objects to create the Web Page content" h1 { text("welcome") } link { Title = "Google" Link = "http://www.google.com" } div { id = "div1" style = stylegradient(30) + stylesize("50%","50%") text("Outer Div") div { id = "div2" color = "white" backgroundcolor = "green" width = "50%" height = "50%" marginleft = "5%" margintop = "5%" text("Inner Div") } } div { id = "div3" color = "black" backgroundcolor = "silver" width = "100%" height = "100%" text("Form") form { method = "POST" Action = "helloworld.ring" Table { style = stylewidth("100%") + stylegradient(24) TR { (continues on next page) 52.19. Generating Pages using Objects 558
Ring Documentation, Release1.16 52.20 HtmlPage Class Using this class we can create HTML documents without printing the output to the standard output So instead of using the WebLib in Web Applications only We can use it in Console/GUI/Mobile Applications too Example: load "stdlib.ring" load "weblib.ring" import System.Web (continues on next page) 52.20. HtmlPage Class 562
602.
Ring Documentation, Release1.16 (continued from previous page) func main mypage = new HtmlPage { h1 { text("Customers Report") } Table { style = stylewidth("100%") + stylegradient(4) TR { TD { WIDTH="10%" text("Customers Count : " ) } TD { text (100) } } } Table { style = stylewidth("100%") + stylegradient(26) TR { style = stylewidth("100%") + stylegradient(24) TD { text("Name " ) } TD { text("Age" ) } TD { text("Country" ) } TD { text("Job" ) } TD { text("Company" ) } } for x = 1 to 100 TR { TD { text("Test" ) } TD { text("30" ) } TD { text("Egypt" ) } TD { text("Sales" ) } TD { text("Future" ) } } next } } write("report.html",mypage.output()) 52.21 Using Bootstrap Library using Functions The next example uses the Bootstrap JavaScript Library when generating the HTML page. #!ring -cgi Load "weblib.ring" Import System.Web Func Main new BootstrapPage { divstart([ :class = "container" ]) (continues on next page) 52.21. Using Bootstrap Library using Functions 563
603.
Ring Documentation, Release1.16 (continued from previous page) divstart([ :class = "jumbotron" ]) h1("Bootstrap Page") divend() divstart([ :class = :row ]) divstart([ :class = "col-sm-4" ]) h3("Welcome to the Ring programming language") p([ :text = "Using a scripting language is very fun!" ]) divend() divstart([ :class = "col-sm-4" ]) h3("Welcome to the Ring programming language") p([ :text = "using a scripting language is very fun!" ]) divend() divstart([ :class = "col-sm-4" ]) h3("Welcome to the Ring programming language") p([ :text = "using a scripting language is very fun!" ]) divend() divend() divend() } Screen Shot: 52.21. Using Bootstrap Library using Functions 564
604.
Ring Documentation, Release1.16 52.22 Using Bootstrap Library using Objects The next example uses the Bootstrap JavaScript Library when generating the HTML page. Instead of using functions to generate the HTML elements, we will use objects. #!ring -cgi Load "weblib.ring" Import System.Web Func Main BootStrapWebPage() { div { classname = :container div { classname = :jumbotron H1 { text("Bootstrap Page") } } div { classname = :row for x = 1 to 3 div { classname = "col-sm-4" H3 { html("Welcome to the Ring programming language") } P { html("Using a scripting language is very fun!") } } next } div { classname = :row div { classname = "col-sm-4" Button { classname = "btn btn-info btn-lg" datatoggle= "modal" datatarget = "#myModal" text("Open Large Modal") } } div { classname = "col-sm-4" Button { classname = "btn btn-default btn-lg" text("default") } Button { classname = "btn btn-primary btn-md" text("primary") } Button { classname = "btn btn-success btn-sm" text("success") } Button { classname = "btn btn-info btn-xs" text("info") } Button { classname = "btn btn-warning" text("warning") } Button { classname = "btn btn-danger" text("danger") } Button { classname = "btn btn-link" text("link") } (continues on next page) 52.22. Using Bootstrap Library using Objects 565
Ring Documentation, Release1.16 (continued from previous page) text("close") } } } } } } } Screen Shot: 52.23 CRUD Example using MVC The next example uses the weblib.ring & datalib.ring. The datalib.ring contains classes for creating database applications using MVC pattern. In this example we create an object from the SalaryController class then call the Routing method. We define the website variable to contains the basic url of the page. When we create the SalaryModel class from the ModelBase class, the salary table will be opened and the columns data will be defined as attributes in the model class. The SalaryView class create an object from the SalaryLanguageEnglish class to be used for translation. The method AddFuncScript is used to call the form for adding/modifying record data. The method FormViewContent is used to determine the controls in the form when we add or modify a record. 52.23. CRUD Example using MVC 567
607.
Ring Documentation, Release1.16 #!ring -cgi Load "weblib.ring" Load "datalib.ring" Import System.Web website = "ex24.ring" New SalaryController { Routing() } Class SalaryModel from ModelBase Class SalaryController From ControllerBase Class SalaryView From ViewBase oLanguage = new SalaryLanguageEnglish Func AddFuncScript oPage,oController return oPage.scriptfuncajax("myadd",oController.cMainURL+ oController.cOperation+"=add","mysubpage") Func FormViewContent oController,oTranslation,oPage return [ [ oTranslation.aColumnsTitles[2], "textbox", "name", oController.oModel.Name, oPage.stylewidth("100%") ], [ oTranslation.aColumnsTitles[3], "textbox", "salary", oController.oModel.Salary, oPage.stylewidth("50%") ] ] Class SalaryLanguageEnglish cTitle = "Salary Table" cBack = "back" aColumnsTitles = ["ID","Name","Salary"] cOptions = "Options" cSearch = "Search" comboitems = ["Select Option...","Edit","Delete"] cAddRecord = "Add Record" cEditRecord = "Edit Record" cRecordDeleted = "Record Deleted!" aMovePages = ["First","Prev","Next","Last"] cPage = "Page" cOf = "of" cRecordsCount = "Records Count" cSave = "Save" temp = new page cTextAlign = temp.StyleTextRight() cNoRecords = "No records!" Screen Shot: 52.23. CRUD Example using MVC 568
Ring Documentation, Release1.16 52.24 Users registration and Login We have the users classes (Model, View & Controller) to deal with the users data like username & email. The next code is stored in ex25_users.ring Class UsersModel from ModelBase cSearchColumn = "username" Class UsersController From ControllerBase aColumnsNames = ["id","username","email"] Func UpdateRecord oModel.id = aPageVars[cRecID] oModel.updatecolumn("username", aPageVars[:username] ) oModel.updatecolumn("email", aPageVars[:email] ) oView.UpdateView(self) Class UsersView from ViewBase oLanguage = new UsersLanguageEnglish Func AddFuncScript oPage,oController return oPage.scriptfunc("myadd",oPage.scriptredirection("ex26.ring")) Func FormViewContent oController,oTranslation,oPage return [ [oTranslation.aColumnsTitles[2],"textbox","username", oController.oModel.UserName,oPage.stylewidth("100%")], [oTranslation.aColumnsTitles[3],"textbox","email", oController.oModel.Email,oPage.stylewidth("50%")] ] Class UsersLanguageEnglish cTitle = "Users Table" cBack = "back" aColumnsTitles = ["ID","User Name","Email"] cOptions = "Options" cSearch = "Search" comboitems = ["Select Option...","Edit","Delete"] cAddRecord = "Add Record" cEditRecord = "Edit Record" cRecordDeleted = "Record Deleted!" aMovePages = ["First","Prev","Next","Last"] cPage = "Page" cOf = "of" cRecordsCount = "Records Count" cSave = "Save" temp = new page cTextAlign = temp.StyleTextRight() cNoRecords = "No records!" In the file ex25.ring we load ex25_users.ring then create an object from UsersController class. Using the created object, we call the routing method. #!ring -cgi Load "weblib.ring" (continues on next page) 52.24. Users registration and Login 570
610.
Ring Documentation, Release1.16 (continued from previous page) Load "datalib.ring" Load "ex25_users.ring" Import System.Web website = "ex25.ring" New UsersController { Routing() } Screen Shot: See the next code for the registration page #!ring -cgi Load "weblib.ring" Load "datalib.ring" Import System.Web website = "ex26.ring" new page { boxstart() text( "Register") newline() boxend() divstart([:style = stylegradient(6) + stylesize("100%","95%") ]) link([ :url = website, :title = "back" , :style = stylecolor("white")]) newline() divstart([ :style= styledivcenter("500","160") + stylegradient(52) ]) formpost("ex27.ring") tablestart([ :Style = stylemarginleft("2%") + stylemargintop("2%") + stylewidth("90%") ]) rowstart([]) cellstart([:style = stylewidth("20%") + styleheight(30)]) text("User Name") (continues on next page) 52.24. Users registration and Login 571
Ring Documentation, Release1.16 The Registration response #!ring -cgi Load "weblib.ring" Load "datalib.ring" Load "ex25_users.ring" Import System.Web oUser = new UsersModel oUser.Connect() if oUser.findwith("username",aPageVars["username"]) new page { text("The user name is already registered") } return ok if oUser.findwith("email",aPageVars["email"]) new page { text("This email is already registered") } return ok aPageVars["salt"] = str2hex(RandBytes(32)) aPageVars["pwhash"] = sha256(aPagevars["password"]+aPageVars["salt"]) aPageVars["sessionid"] = str2hex(randbytes(32)) oUser.Insert() new page { cookie("sessionid",aPageVars["sessionid"]) (continues on next page) 52.24. Users registration and Login 573
Ring Documentation, Release1.16 Screen Shot: The response page #!ring -cgi Load "weblib.ring" Load "datalib.ring" Load "ex25_users.ring" Import System.Web oUser = new UsersModel oUser.Connect() lResult = oUser.FindWith("username",aPageVars["username"]) new page { if lResult if sha256(aPagevars["password"]+oUser.Salt) = oUser.pwhash text ("Correct Password!") aPageVars["sessionid"] = str2hex(randbytes(32)) oUser.UpdateColumn("sessionid",aPageVars["sessionid"]) cookie("sessionid",aPageVars["sessionid"]) else text ("Bad password!") ok else text("Bad User Name!") ok } oUser.Disconnect() The next code for checking if the user needs to login or not 52.24. Users registration and Login 575
615.
Ring Documentation, Release1.16 #!ring -cgi Load "weblib.ring" Load "datalib.ring" Load "ex25_users.ring" Import System.Web oUser = new UsersModel oUser.Connect() lResult = oUser.FindWith("sessionid",aPageVars["sessionid"]) new page { if lResult text("User Name : " + oUser.username ) else text("Please Login First!") ok } oUser.Disconnect() 52.25 Database, ModelBase & ControllerBase classes In this section we will see some code from datalib.ring The next code presents the Database, ModelBase & ControllerBase classes Import System.Web Class Database cServer = "localhost" cUserName = "root" cPassword = "root" cDatabase = "mahdb" Func Connect con = mysql_init() mysql_connect(con, cServer, cUserName, cPassWord,cDatabase) Func Disconnect mysql_close(con) Func Query cQuery mysql_query(con,cQuery) Func QueryResult return mysql_result(con) Func QueryResultWithColumns # return columns names + query result return mysql_result2(con) (continues on next page) 52.25. Database, ModelBase & ControllerBase classes 576
616.
Ring Documentation, Release1.16 (continued from previous page) Func QueryValue aResult = mysql_result(con) if islist(aResult) and len(aResult) >= 1 aResult = aResult[1] if len(aResult) >= 1 return aResult[1] ok ok return 0 Func EscapeString x if isstring(x) return MySQL_Escape_String(con,x) else return MySQL_Escape_String(con,string(x)) ok Private con = NULL Class ModelBase from Database cTableName = "" cSearchColumn = "name" aColumns = [] aQueryResult = [] ID = 0 # set table name from class name classname = lower(classname(self)) if right(classname,5) = :model cTablename = left(classname,len(classname)-5) ok Func Insert cValues = "" for x in aColumns cValues += "'" + EscapeString(aPageVars[x]) + "'," Next cValues = left(cValues,len(cValues)-1) # remove last comma cColumns = "" for x in aColumns cColumns += x + "," next cColumns = left(cColumns,len(cColumns)-1) query("insert into " + cTableName + "("+cColumns+") values (" + cValues + ")" ) Func Update nID cStr = "" for x in aColumns cStr += x + " = '" + EscapeString(aPageVars[x]) + "' , " # the space after comma is necessary Next cStr = left(cStr,len(cStr)-2) (continues on next page) 52.25. Database, ModelBase & ControllerBase classes 577
617.
Ring Documentation, Release1.16 (continued from previous page) query("update " + cTableName + " set " + cStr + " where id = " + nID ) Func UpdateColumn cColumn,cValue query("update " + cTableName + " set " + cColumn + " = '" + EscapeString(cValue) + "' where id = " + self.ID ) Func Count cValue query("SELECT count(*) FROM " + cTableName + " where "+cSearchColumn+" like '" + EscapeString(cValue) + "%'") return queryValue() Func Read nStart,nRecordsPerPage query("SELECT * FROM "+ cTableName+" limit " + EscapeString(nStart) + "," + EscapeString(nRecordsPerPage) ) aQueryResult = queryResult() Func Search cValue,nStart,nRecordsPerPage query("SELECT * FROM "+ cTableName+" where "+cSearchColumn+" like '" + EscapeString(cValue) + "%'" + " limit " + EscapeString(nStart) + "," + EscapeString(nRecordsPerPage) ) aQueryResult = queryResult() Func Find nID query("select * from " + cTableName + " where id = " + EscapeString(nID) ) aResult = queryResult()[1] # move the result from the array to the object attributes ID = nID cCode = "" for x = 2 to len(aResult) cCode += aColumns[x-1] + " = hex2str('" + str2hex(aResult[x]) + "')" + nl next eval(cCode) Func FindWith cColumn,cValue query("select * from " + cTableName + " where "+cColumn+" = '" + EscapeString(cValue) + "'" ) aResult = queryResult() if len(aResult) > 0 aResult = aResult[1] else return 0 ok # move the result from the array to the object attributes ID = aResult[1] cCode = "" for x = 2 to len(aResult) cCode += aColumns[x-1] + " = hex2str('" + str2hex(aResult[x]) + "')" + nl next eval(cCode) return 1 (continues on next page) 52.25. Database, ModelBase & ControllerBase classes 578
618.
Ring Documentation, Release1.16 (continued from previous page) Func Delete ID query("delete from " + cTableName + " where id = " + EscapeString(ID) ) Func Clear cCode = "" for x in aColumns cCode += x + ' = ""' + nl next eval(cCode) Func LoadModel # create the columns array query("SELECT * FROM "+ cTableName + " limit 0,1") aQueryResult = QueryResultWithColumns()[1] for x = 2 to len(aQueryResult) aColumns + lower(trim(aQueryResult[x])) next # create attribute for each column for x in aColumns addattribute(self,x) next Func Connect Super.Connect() if nLoadModel = 0 nLoadModel = 1 LoadModel() ok private nLoadModel = 0 Class ControllerBase nRecordsPerPage = 5 nRecordsCount = 0 nPagesCount = 0 nActivePage = 0 # Dynamic creation of oView = new tablenameView and oModel = new tablename.Model classname = lower(classname(self)) if right(classname,10) = :controller tablename = left(classname,len(classname)-10) cCode = "oView = new " + tablename+"View" + nl cCode += "oModel = new " + tablename+"Model" + nl eval(cCode) oModel.connect() ok cSearchName = "searchname" (continues on next page) 52.25. Database, ModelBase & ControllerBase classes 579
619.
Ring Documentation, Release1.16 (continued from previous page) cPart = "part" cPageError = "The page number is not correct" cLast = "last" cOperation = "operation" cRecID = "recid" aColumnsNames = ["id"] for t in oModel.aColumns aColumnsNames + t next cMainURL = website + "?" func Routing switch aPageVars[cOperation] on NULL showtable() on :add addrecord() on :save saverecord() on :delete deleterecord() on :edit editrecord() on :update updaterecord() off func ShowTable nRecordsCount = oModel.Count( aPageVars[cSearchName] ) nPagesCount = ceil(nRecordsCount / nRecordsPerPage) if aPageVars[cPart] = cLast aPageVars[cPart] = string(nPagesCount) ok nActivePage = number(aPageVars[cPart]) if nActivePage = 0 nActivePage = 1 ok if ( nActivePage > nPagesCount ) and nRecordsCount > 0 ErrorMsg(cPageError) return ok nStart = (nActivePage-1)*nRecordsPerPage if aPageVars[cSearchName] = NULL oModel.Read( nStart,nRecordsPerPage ) else oModel.Search( aPageVars[cSearchName],nStart,nRecordsPerPage ) ok oView.GridView(self) func AddRecord oModel.clear() oView.FormViewAdd(Self,:save,false) # false mean don't include record id (continues on next page) 52.25. Database, ModelBase & ControllerBase classes 580
620.
Ring Documentation, Release1.16 (continued from previous page) func SaveRecord oModel.Insert() oView.SaveView(self) func EditRecord oModel.Find( aPageVars[cRecID] ) oView.FormViewEdit(Self,:update,true) # true mean include record id func UpdateRecord oModel.update( aPageVars[cRecID] ) oView.UpdateView(self) func DeleteRecord oModel.Delete( aPageVars[cRecID] ) oView.DeleteView() func braceend oModel.Disconnect() 52.26 WebLib API In this section we will see the web library functions, classes and methods. Function Parameters Description LoadVars None Save the request parameters and cookies to aPageVars List WebPage None Create new object from the WebPage Class BootStrapWebPage None Create new object from the BootStrapWebPage Class HTMLSpecialChars cString Encode Special characters to HTML equivalent Template cFile,oObject Execute Ring Code in cFile after accessing oObject using {} Alert cMessage Generate HTML Web Page that display cMessage using JavaScript Alert() HTML2PDF cString Generate and Display PDF File from HTML String (cString) The Package System.Web contains the next classes Class Name Description Application Contains methods for Encoding, Decoding, Cookies & More. Page Contains methods to generate HTML pages. ScriptFunctions Contains methods to generate some JavaScript Functions. StyleFunctions Contains methods to generate CSS. PageBuffer Generate HTML Page in memory (don’t print the output). HTML2PDF Generate PDF File from HTML code. BootStrapPage Using BootStrap Library. WebPage Generate page using objects for each element. HtmlPage Like WebPage but doesn’t print the output to stdout. BootStrapWebPage Generate page using objects, using BootStrap Library. continues on next page 52.26. WebLib API 581
621.
Ring Documentation, Release1.16 Table 1 – continued from previous page Class Name Description ObjsBase Parent Class for page objects. NewObjectsFunctions Methods to create new objects in the page or element. H1 Wraps HTML H1. H2 Wraps HTML H2. H3 Wraps HTML H3. H4 Wraps HTML H4. H5 Wraps HTML H5. H6 Wraps HTML H6. P Wraps HTML P. Link Wraps HTML link. NewLine Wraps HTML NewLine. Div Wraps HTML Div. Form Wraps HTML Form. Input Wraps HTML Input. TextArea Wraps HTML TextArea. Select Wraps HTML Select. Option Wraps HTML Option. Image Wraps HTML Image. UL Wraps HTML UL. LI Wraps HTML LI. Table Wraps HTML Table. TR Wraps HTML TR. TD Wraps HTML TD. TH Wraps HTML TH. Audio Wraps HTML Audio. Video Wraps HTML Video. Nav Wraps HTML Nav. Span Wraps HTML Span. Button Wraps HTML Button. 52.27 Application Class Method Parameters Description DecodeString cString Decode request parameters Decode cString Decode multipart/form-data GetFileName aArray,cVar Get File Name in aArray using cVar SetCookie name,value,expires,path,domain,secure Set Cookie Cookie name,value Set Cookie using name and value only GetCookies None Get Cookies URLEncode cString URL Encode ScriptLibs None Add JavaScript Libraries like BootStrap Print None Print Page Content Style cStyle Add cStyle to page CSS content StartHTML None Add HTTP Header to page content The method DecodeString is used to get HTTP request parameters. The methods Decode and GetFileName are used for uploading files. 52.27. Application Class 582
622.
Ring Documentation, Release1.16 The methods SetCookie, Cookie & GetCookies are used for adding and reading cookies. The methods StartHTML, ScriptsLibs, Style & Print are used for page structure and JS/CSS support. The method URLEncode is used to encode a URL to be used in HTML pages. 52.28 Page Class Method Parameters Description text x add HTMLSpecialChars(x) to page content (accept strings and numbers) html cString add html code to page content h1 x add x to page content between <h1> and </h1> h2 x add x to page content between <h2> and </h2> h3 x add x to page content between <h3> and </h3> h4 x add x to page content between <h4> and </h4> h5 x add x to page content between <h5> and </h5> h6 x add x to page content between <h6> and </h6> p aPara HTML <p> </p>, uses aPara List as Hash to get attributes NewLine None add <br /> to page content AddAttributes aPara Convert aPara list as hash to HTML element attributes Link aPara HTML <a href> and </a>, uses aPara List as Hash to get attributes Image aPara HTML <img>, uses aPara List as Hash to get attributes Button aPara HTML <input type=”button”>, uses aPara List as Hash to get attributes ButtonLink aPara HTML <input type=”button”>, uses link attribute to navigate to link Textbox aPara HTML <input type=”text”>, uses aPara List as Hash to get attributes Editbox aPara HTML <textarea> and </textarea>, uses aPara to get attributes Combobox aPara HTML <select>, uses items attribute as list for <option> Listbox aPara HTML <select multiple=’multiple’>, uses items attribute for <option> ulstart aPara HTML <ul> ulend aPara HTML </ul> listart aPara HTML <li> liend aPara HTML </li> List2UL aList Generate HTML <ul> including items from Ring List items DivStart aPara HTML <div>, uses aPara List as Hash to get attributes NavStart aPara HTML <nav>, uses aPara List as Hash to get attributes SpanStart aPara HTML <span>, uses aPara List as Hash to get attributes BoxStart None Generate Div with black background to be used as page header DivEnd None HTML </div> NavEnd None HTML </nav> SpanEnd None HTML </span> BoxEnd None HTML </div>, the same as divend() FormStart cAction HTML <form>, with cAction as the action attribute or an empty value FormPost cAction HTML <form method=”post”> , with cAction as the action attribute FormEnd None HTML </form> Submit aPara HTML <input type=”submit”> Hidden cName,cValue HTML <input type=”hidden”> FormUpload x HTML Form, method=”post” enctype=”multipart/form-data” and x = action UploadFile x HTML <input type=”file”> and name = x Video aPara HTML <video> Audio aPara HTML <audio> continues on next page 52.28. Page Class 583
623.
Ring Documentation, Release1.16 Table 2 – continued from previous page Method Parameters Description GetColor aPara Select Color Radio aPara HTML <input type=”radio”> Checkbox aPara HTML <input type=”checkbox”> Spinner aPara HTML <input type=”number”> Slider aPara HTML <input type=”range”> TableStart aPara HTML <table> TableEnd None HTML </table> RowStart aPara HTML <tr> RowEnd None HTML </tr> CellStart aPara HTML <td> CellEnd None HTML </td> HeaderStart aPara HTML <th> HeaderEnd None HTML </th> aPara in the page methods is a list contains attributes and values. Using aPara we can set values for the next attributes classname id name align style dir value onclick oncontextmenu ondblclick onmousedown onmouseenter onmouseleave onmousemove onmouseover onmouseout onmouseup onkeydown onkeypress onkeyup onabort onbeforeunload onerror onhashchange onload onpageshow onpagehide onresize onscroll onunload onblur onchange onfocus onfocusin onfocusout oninput oninvalid onreset onsearch onselect onsubmit ondrag ondragend ondragenter ondragleave ondragover ondragstart ondrop oncopy oncut onpaste onafterprint onbeforeprint oncanplay oncanplaythrough ondurationchange onemptied onended onloadeddata onloadedmetadata onloadstart onpause onplay onplaying onprogress onratechange onseeked onseeking onstalled onsuspend ontimeupdate onvolumechange onwaiting animationend animationiteration animationstart transitionend onmessage onopen onmousewheel ononline onoffline onpostate onshow onstorage ontoggle onwheel ontouchcancel ontouchend ontouchmove ontouchstart color opacity background backgroundattachment backgroundcolor backgroundimage backgroundposition backgroundrepeat backgroundclip backgroundorigin backgroundsize border borderbottom borderbottomcolor borderbottomleftradius borderbottomrightradius borderbottomstyle borderbottomwidth bordercolor borderimage borderimageoutset borderimagerepeat borderimageslice borderimagesource borderimagewidth borderleft borderleftcolor borderleftstyle borderleftwidth borderradius borderright borderrightcolor borderrightstyle borderrightwidth borderstyle bordertop bordertopcolor bordertopleftradius bordertoprightradius bordertopstyle bordertopwidth borderwidth boxdecorationbreak boxshadow bottom clear clip display float height left margin marginbottom marginleft marginright margintop maxheight maxwidth minheight minwidth overflow overflowx overflowy padding paddingbottom paddingleft paddingright paddingtop position right top visibility width verticalalign zindex aligncontent alignitems alignself flex flexbasis flexdirection flexflow flexgrow flexshrink flexwrap justifycontent order hangingpunctuation hyphens letterspacing linebreak lineheight overflowwrap tabsize textalign textalignlast textcombineupright textindent textjustify texttransform whitespace wordbreak wordspacing wordwrap textdecoration textdecorationcolor textdecorationline textdecorationstyle textshadow textunderlineposition @fontface @fontfeaturevalues font fontfamily fontfeaturesettings fontkerning fontlanguageoverride fontsize fontsizeadjust fontstretch fontstyle fontsynthesis fontvariant fontvariantalternates fontvariantcaps fontvarianteastasian fontvariantligatures fontvariantnumeric fontvariantposition fontweight direction textorientation unicodebidi writingmode bordercollapse borderspacing captionside emptycells tablelayout counterincrement counterreset liststyle liststyleimage liststyleposition liststyletype @keyframes animation animationdelay animationdirection (continues on next page) 52.28. Page Class 584
624.
Ring Documentation, Release1.16 (continued from previous page) animationduration animationfillmode animationiterationcount animationname animationplaystate animationtimingfunction backfacevisibility perspective perspectiveorigin transform transformorigin transformstyle transition transitionproperty transitionduration transitiontimingfunction transitiondelay boxsizing content cursor imemode navdown navindex navleft navright navup outline outlinecolor outlineoffset outlinestyle outlinewidth resize textoverflow breakafter breakbefore breakinside columncount columnfill columngap columnrule columnrulecolor columnrulestyle columnrulewidth columnspan columnwidth columns widows orphans pagebreakafter pagebreakbefore pagebreakinside marks quotes filter imageorientation imagerendering imageresolution objectfit objectposition mask masktype mark markafter markbefore phonemes rest restafter restbefore voicebalance voiceduration voicepitch voicepitchrange voicerate voicestress voicevolume marqueedirection marqueeplaycount marqueespeed marqueestyle datatoggle dataride datatarget dataslideto dataslide datadismiss dataplacement datacontent datatrigger dataspy dataoffset dataoffsettop 52.29 ScriptFunctions Class This class contains methods for adding JavaScript code to the generated web page. The class methods are merged to the Page class, so we can use the next methods with page objects directly. Method Parameters Description Script cCode Add cCode string between <script> and </script> ScriptRedirec- tion cURL set window.location to cURL ScriptFunc cFuncName,cCode Define function cFuncName that contains cCode ScriptFuncAlert cFuncName,cMsg Define function cFuncName that uses alert() to print cMsg ScriptFuncAjax cFuncName,cLink,cDiv Define function cFuncName that load cLink in cDiv ScriptFuncClean cFuncName,cDiv Define function cFuncName that clear the cDiv ScriptFuncSe- lect cF,aL,cD,cR,cGR,cFC,nTO,cL1,cL2 Used to Edit/Delete Grid Record ScriptScroll- Fixed cDiv,nSize Set cDiv as Fixed Div with Size = nSize 52.30 StyleFunctions Class This class contains methods for adding CSS to the generated web page. Like ScriptFunctions Class, The StyleFunctions class methods are merged to the Page class, so we can use the next methods with page objects directly. 52.29. ScriptFunctions Class 585
625.
Ring Documentation, Release1.16 Method Parameters Description StyleFloatLeft None Return float: left ; StyleFloatRight None Return float: right ; StyleSizeFull None Return width: 100% ; height: 100% ; Stylecolor x Return ” color: ” + x + ” ; “ Stylebackcolor x Return ” background-color: ” + x + ” ;” StyleTextCenter None Return “text-align: center ;” StyleTextRight None Return “text-align: right ;” StyleTextLeft None Return “text-align: left ;” StyleSize x,y Return ” width: ” + x + ” ; height: ” + y + ” ;” StyleWidth x Return ” width: ” + x + ” ;” StyleHeight x Return ” height: ” + x + ” ;” StyleTop x Return ” top: ” + x + ” ;” StyleLeft x Return ” Left: ” + x + ” ;” StylePos x,y Return ” top: ” + x + ” ;” + ” Left: ” + y + ” ;” StyleHorizontalCenter None Return ” margin-right:auto ; margin-left:auto; “ StyleMarginTop x Return ” margin-top: ” + x + ” ;” StyleMarginRight x Return ” margin-right: ” + x + ” ;” StyleMarginLeft x Return ” margin-left: ” + x + ” ;” StyleDivCenter nWidth,nHeight Create Div in the center of the page StyleAbsolute None Return ” position:absolute ;” StyleFixed None Return ” position:fixed ;” StyleZIndex x Return ” z-index: ” + x + ” ;” StyleFontSize x Return ” font-size: ” + x + ” ;” StyleGradient x Generate Gradient (x values from 1 to 60) StyleTable None Set table properties StyleTableRows id Set different color to even and odd rows in the table StyleTableNoBorder None Return ” border-style: none;” 52.31 WebPage Class We use braces to access the active WebPage object attributes Each one of these attribute will return a new object to access again using braces. 52.31. WebPage Class 586
626.
Ring Documentation, Release1.16 Attribute Description H1 Wraps HTML H1. H2 Wraps HTML H2. H3 Wraps HTML H3. H4 Wraps HTML H4. H5 Wraps HTML H5. H6 Wraps HTML H6. P Wraps HTML P. Link Wraps HTML link. NewLine Wraps HTML NewLine. Div Wraps HTML Div. Form Wraps HTML Form. Input Wraps HTML Input. TextArea Wraps HTML TextArea. Select Wraps HTML Select. Option Wraps HTML Option. Image Wraps HTML Image. UL Wraps HTML UL. LI Wraps HTML LI. Table Wraps HTML Table. TR Wraps HTML TR. TD Wraps HTML TD. TH Wraps HTML TH. Audio Wraps HTML Audio. Video Wraps HTML Video. Nav Wraps HTML Nav. Span Wraps HTML Span. Button Wraps HTML Button. 52.32 HtmlPage Class The same as the WebPage class with the next changes (1) No output to the stdout (2) Provide the Output Method to get the output Syntax: output() ---> The output as string 52.32. HtmlPage Class 587
627.
CHAPTER FIFTYTHREE DEPLOYING WEB APPLICATIONSIN THE CLOUD In this chapter we will learn about deploying Ring Web Applications in the Cloud using Heroku 53.1 Introduction We created a new project and tutorial to explain how to deploy Ring web applications in the Cloud using Heroku Demo : http://testring.herokuapp.com/ Project : https://github.com/ring-lang/RingWebAppOnHeroku Heroku Website : https://www.heroku.com/ 588
628.
Ring Documentation, Release1.16 53.2 Usage To use this project and deploy it on Heroku (1) Create Heroku account (2) Open your Heroku account and create new application Example : testring Note (You have to select a unique name for your application) (3) Open the command prompt, Create new folder : MyApp md MyApp (4) Open the application folder cd MyApp (5) Clone this project using Git (Don’t forget the dot in the end to clone in the current directory) git clone https://github.com/ring-lang/RingWebAppOnHeroku . (6) Login to Heroku (Enter your Email and Password) heroku login (7) Add heroku (remote) to your Git project change testring to your application name heroku git:remote -a testring (8) Set the buildpacks (So Heroku can know how to support your project) heroku buildpacks:add --index 1 https://github.com/ring-lang/heroku-buildpack-apt heroku buildpacks:add --index 2 https://github.com/ring-lang/heroku-buildpack-ring (9) Now build your project and deploy it git push heroku master (10) Test your project (In the browser) heroku open 53.3 Ring source code files and permissions To be able to run your new Ring scripts, Set the permission of the file to be executable using Git For example, if you created a file : myscript.ring git update-index --chmod=+x myscript.ring git commit -m "Update file permission" 53.2. Usage 589
629.
Ring Documentation, Release1.16 If you are using TortoiseGit, From windows explorer, select the file Right click —> Properties —> Git —> Executable (+x) Then commit and deploy! 53.4 Hello World program file : ringapp/helloworld.ring To run it : http://testring.herokuapp.com/ringapp/helloworld.ring #!/app/runring.sh -cgi see "content-type: text/html" +nl+nl see "Hello, World!" + nl file : ringapp/helloworld2.ring To run it : http://testring.herokuapp.com/ringapp/helloworld2.ring #!/app/runring.sh -cgi load "weblib.ring" import System.Web new page { text("Hello, World!") } 53.5 Application Database When you deploy the application, Everything will works directly! No change is required, but in practice, You will need to update the next files to use your database There are two scripts to interact with the database (We are using PostgreSQL in the cloud) You will need to update the connection string in these files if you will use another database • file: ringapp/database/newdb.ring (We run it using the browser for one time to create the tables) • file: ringapp/datalib.ring (Class: Database) In your practical projects, You can write better code (To be able to change the database) Also you can create configuration file (To write the connection string in one place) Database service : https://www.heroku.com/postgres 53.4. Hello World program 590
630.
Ring Documentation, Release1.16 53.6 Deploying after updates Just use Git and commit then push to heroku file: build.bat contains the next commands for quick tests git add . git commit -m "Update RingWebAppOnHeroku" git push heroku master heroku open 53.7 Local Tests Local tests using Ring Notepad on Windows (Using local Apache Web Server) Replace the first line in the file : ringapp/index.ring with #!ring -cgi Then run it from Ring Notepad (Ctrl+F6) 53.6. Deploying after updates 591
631.
CHAPTER FIFTYFOUR GRAPHICS AND 2DGAMES PROGRAMMING USING RINGALLEGRO In this chapter we will learn how to use the allegro game programming library in our Ring applications. We have the file gamelib.ring that load the DLL library that contains wrappers for the Allegro functions Load "allegro.rh" if iswindows() LoadLib("ring_allegro.dll") but ismacosx() LoadLib("libringallegro.dylib") else LoadLib("libringallegro.so") ok The file gamelib.ring uses the Load instruction to execute the file allegro.rh which is a ring source code file con- tains constants to be used in our programs. Then using the function LoadLib() we can load the DLL library “ring_allegro.dll”. To write portable code we can change the gamelib.ring to check the platform before loading the DLL/So file. 54.1 Drawing, Animation and Input The next example uses the Allegro library for drawing, moving objects on the screen and getting input from the keyboard and the mouse. Load "gamelib.ring" al_init() al_init_image_addon() display = al_create_display(640,480) al_show_native_message_box(display, "Hello", "Welcome", "Using Allegro from the Ring programming language", "", 0); al_clear_to_color(al_map_rgb(0,0,255)) BOUNCER_SIZE = 40 bouncer_x = 10 bouncer_y = 20 bouncer = al_create_bitmap(BOUNCER_SIZE, BOUNCER_SIZE) al_set_target_bitmap(bouncer) (continues on next page) 592
Ring Documentation, Release1.16 (continued from previous page) exit on ALLEGRO_EVENT_TIMER # Animation if bouncer_x < 0 or bouncer_x > SCREEN_W - BOUNCER_SIZE bouncer_dx = -bouncer_dx ok if bouncer_y < 0 or bouncer_y > SCREEN_H - BOUNCER_SIZE bouncer_dy = -bouncer_dy ok bouncer_x += bouncer_dx bouncer_y += bouncer_dy # Keyboard if key[KEY_UP] and bouncer_y >= 4.0 bouncer_y -= 4.0 ok if key[KEY_DOWN] and bouncer_y <= SCREEN_H - BOUNCER_SIZE - 4.0 bouncer_y += 4.0 ok if key[KEY_LEFT] and bouncer_x >= 4.0 bouncer_x -= 4.0 ok if key[KEY_RIGHT] and bouncer_x <= SCREEN_W - BOUNCER_SIZE - 4.0 bouncer_x += 4.0 ok redraw = true on ALLEGRO_EVENT_MOUSE_AXES bouncer_x = al_get_allegro_event_mouse_x(ev) bouncer_y = al_get_allegro_event_mouse_y(ev) on ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY bouncer_x = al_get_allegro_event_mouse_x(ev) bouncer_y = al_get_allegro_event_mouse_y(ev) on ALLEGRO_EVENT_MOUSE_BUTTON_UP exit on ALLEGRO_EVENT_KEY_DOWN switch al_get_allegro_event_keyboard_keycode(ev) on ALLEGRO_KEY_UP key[KEY_UP] = true on ALLEGRO_KEY_DOWN key[KEY_DOWN] = true on ALLEGRO_KEY_LEFT key[KEY_LEFT] = true on ALLEGRO_KEY_RIGHT key[KEY_RIGHT] = true off on ALLEGRO_EVENT_KEY_UP switch al_get_allegro_event_keyboard_keycode(ev) on ALLEGRO_KEY_UP key[KEY_UP] = false on ALLEGRO_KEY_DOWN key[KEY_DOWN] = false on ALLEGRO_KEY_LEFT (continues on next page) 54.1. Drawing, Animation and Input 594
634.
Ring Documentation, Release1.16 (continued from previous page) key[KEY_LEFT] = false on ALLEGRO_KEY_RIGHT key[KEY_RIGHT] = false on ALLEGRO_KEY_ESCAPE exit off off if redraw and al_is_event_queue_empty(event_queue) redraw = false al_clear_to_color(al_map_rgb(0,0,0)) al_draw_bitmap(bouncer, bouncer_x, bouncer_y, 0) al_flip_display() ok callgc() end al_destroy_timer(timer) al_destroy_allegro_event(ev) al_destroy_allegro_timeout(timeout) al_destroy_event_queue(event_queue) al_destroy_bitmap(bouncer) al_destroy_bitmap(image) al_destroy_display(display) Note: In the previous example we used the function callgc() which is a Ring function to force calling the Garbage collector inside the While/End loop. Program Output: At first the program display a messagebox 54.1. Drawing, Animation and Input 595
635.
Ring Documentation, Release1.16 Then we see two rectangles are moving on the screen 54.1. Drawing, Animation and Input 596
636.
Ring Documentation, Release1.16 Then we see an image displayed on the screen 54.1. Drawing, Animation and Input 597
637.
Ring Documentation, Release1.16 Finally we have one rectangle, and we see it moving all of the time on the screen but we can control it using the Mouse and/or the Keyboard 54.1. Drawing, Animation and Input 598
638.
Ring Documentation, Release1.16 54.2 Using TrueType Fonts In this example we will see how to use TrueType Fonts *.ttf in our Games using Allegro Load "gamelib.ring" al_init() al_init_font_addon() al_init_ttf_addon() display = al_create_display(800,600) al_clear_to_color(al_map_rgb(0,0,255)) font = al_load_ttf_font("pirulen.ttf",14,0 ) al_draw_text(font, al_map_rgb(255,255,255), 10, 10,ALLEGRO_ALIGN_LEFT, "Welcome to the Ring programming language") al_flip_display() al_rest(2) al_destroy_display(display) Screen Shot: 54.2. Using TrueType Fonts 599
639.
Ring Documentation, Release1.16 54.3 Playing Sound Files The next example play a sound file Load "gamelib.ring" al_init() al_install_audio() al_init_acodec_addon() al_reserve_samples(1) sample = al_load_sample( "footstep.wav" ) sampleid = al_new_allegro_sample_id() al_play_sample(sample, 1.0, 0.0,1.0,ALLEGRO_PLAYMODE_LOOP,sampleid) display = al_create_display(640,480) al_clear_to_color(al_map_rgb(0,0,255)) al_flip_display() al_rest(10) (continues on next page) 54.3. Playing Sound Files 600
640.
Ring Documentation, Release1.16 (continued from previous page) al_destroy_allegro_sample_id(sampleid) al_destroy_sample(sample) al_destroy_display(display) al_exit() 54.4 Scaling and Rotating Images The next example display and rotate an image Load "gamelib.ring" al_init() al_init_image_addon() display = al_create_display(640,480) al_set_target_bitmap(al_get_backbuffer(display)) al_clear_to_color(al_map_rgb(255,255,255)) image = al_load_bitmap("man2.jpg") al_draw_rotated_bitmap(image,0,0,250,250,150,0) al_draw_scaled_bitmap(image,0,0,250,250,20,20,400,400,0) al_flip_display() al_rest(2) al_destroy_bitmap(image) al_destroy_display(display) Screen Shot: 54.4. Scaling and Rotating Images 601
641.
Ring Documentation, Release1.16 54.5 Display Transparent Image The next example display image with white background on another image Load "gamelib.ring" al_init() al_init_image_addon() display = al_create_display(640,480) imageback = al_load_bitmap("palace.jpg") al_draw_bitmap(imageback,0,0,0) image = al_load_bitmap("man4.png") al_convert_mask_to_alpha(image,al_map_rgb(255,255,255)) al_draw_bitmap(image,0,0,0) al_flip_display() al_rest(10) al_destroy_bitmap(image) al_destroy_display(display) 54.5. Display Transparent Image 602
642.
Ring Documentation, Release1.16 Screen Shot: 54.6 Using Threads In this example we will learn how to use threads from the Allegro library Load "gamelib.ring" o1 = new mythreads Func Main al_init() for k = 1 to 5 al_create_thread("o1.thread1()") al_create_thread("o1.thread2()") al_create_thread("o1.thread3()") next al_rest(2) Class Mythreads (continues on next page) 54.6. Using Threads 603
643.
Ring Documentation, Release1.16 (continued from previous page) cAppName = "Threads Application" Func Thread1 for x = 1 to 5 see x + nl next See 'Thread(1) : Application Name : ' + cAppName + nl Func Thread2 for x = 1 to 5 see '*****' + x + nl next See 'Thread(2) : Application Name : ' + cAppName + nl Func Thread3 for x = 1 to 5 see '!!!!' + x + nl next See 'Thread(3) : Application Name : ' + cAppName + nl Output: 1 2 3 4 5 Thread(1) : Application Name : Threads Application *****1 *****2 *****3 *****4 *****5 Thread(2) : Application Name : Threads Application !!!!1 !!!!2 !!!!3 !!!!4 !!!!5 Thread(3) : Application Name : Threads Application 1 2 3 4 5 Thread(1) : Application Name : Threads Application !!!!1 !!!!2 !!!!3 !!!!4 !!!!5 Thread(3) : Application Name : Threads Application *****1 *****2 *****3 *****4 *****5 (continues on next page) 54.6. Using Threads 604
644.
Ring Documentation, Release1.16 (continued from previous page) Thread(2) : Application Name : Threads Application *****1 *****2 *****3 *****4 *****5 Thread(2) : Application Name : Threads Application !!!!1 !!!!2 !!!!3 !!!!4 !!!!5 Thread(3) : Application Name : Threads Application 1 2 3 4 5 Thread(1) : Application Name : Threads Application *****1 *****2 *****3 *****1 *****4 *****2 !!!!1 *****5 *****3 1 !!!!2 Thread(2) : Application Name : Threads Application 1 *****4 !!!!1 2 !!!!3 !!!!4 *****5 !!!!2 3 2 !!!!5 Thread(2) : Application Name : Threads Application !!!!3 4 3 Thread(3) : Application Name : Threads Application !!!!4 5 4 !!!!5 Thread(1) : Application Name : Threads Application 5 Thread(3) : Application Name : Threads Application Thread(1) : Application Name : Threads Application 54.6. Using Threads 605
645.
CHAPTER FIFTYFIVE DEMO PROJECT -GAME ENGINE FOR 2D GAMES In this chapter we will learn about using the different programming paradigms in the same project. We will create a simple Game Engine for 2D Games. You can use the Engine directly to create 2D Games for Desktop or Mobile. 55.1 Project Layers The project contains the next layers • Games Layer (Here we will use declarative programming) • Game Engine Classes (Here we will use the Object-Oriented Programming paradigm) • Interface to graphics library (Here we will use procedural programming) • Graphics Library bindings (Here we have RingAllegro and RingLibSDL) 55.2 Graphics Library bindings We already have RingAllegro to use the Allegro game programming library and we have RingLibSDL to use the LibSDL game programming library. Both of RingAllegro and RingLibSDL are created using the C language with the help of the Ring code generator for extensions. Each of them is over 10,000 lines of C code which is generated after writing simple configuration files (That are processed by the code generator). Each configuration file determines the functions names, structures information and constants then the generator process this configuration file to produce the C code and the library that can be loaded from Ring code. Using RingAllegro and RingLibSDL is very similar to using Allegro and LibSDL from C code where you have the same functions but we can build on that using the Ring language features • RingAllegro Source Code : https://github.com/ring-lang/ring/tree/master/extensions/ringallegro • RingLibSDL Source Code : https://github.com/ring-lang/ring/tree/master/extensions/ringsdl 606
646.
Ring Documentation, Release1.16 55.3 Interface to graphics library In this layer we have gl_allegro.ring and gl_libsdl.ring Each library provides the same functions to be used with interacting with the Graphics Library. This layer hides the details and the difference between RingAllegro and RingLibSDL. You have the same functions, Just use it and you can switch between Allegro and LibSDL at anytime. Why ? Allegro is very simple, we can use it to quickly create 2D games for Windows, Linux and MacOS X. In Ring 1.0 we started by supporting Allegro. Also LibSDL is very powerful and popular, very easy to use for Mobile Development. Ring 1.1 comes with support for LibSDL so we can quickly create games for Mobile. Note: We can use just one library for Desktop and Mobile development. • gl_allegro.ring source code : https://github.com/ring-lang/ring/blob/master/libraries/gameengine/gl_allegro. ring • gl_libsdl.ring source code : https://github.com/ring-lang/ring/blob/master/libraries/gameengine/gl_libsdl.ring 55.4 Game Engine Classes The Engine comes with the next classes • GameBase class • Resources class • Game class • GameObject class • Sprite class • Text class • Animate class • Sound class • Map class • Source Code : https://github.com/ring-lang/ring/blob/master/libraries/gameengine/gameengine.ring 55.3. Interface to graphics library 607
647.
Ring Documentation, Release1.16 55.5 Games Layer In this layer we create our games using the Game Engine classes The classes are designed to be used through Declarative Programming. In our games we will use the next classes • Game class • Sprite class • Text class • Animate class • Sound class • Map class Note: Other classes in the engine are for internal use by the engine. We will introduce some examples and three simple games :- • Stars Fighter Game • Flappy Bird 3000 Game • Super Man 2016 Game 55.6 Game Class The next table present the class attributes. Attributes Description FPS Number determines how many times the draw() method will be called per second. FixedFPS Number determines how many times the animate() method will be called per second. Title String determines the window title of the game. Icon String determines the window icon (file name) aObjects List contains all objects in the game shutdown True/False value to end the game loop The next table present the class methods. Method Description refresh() Delete objects. settitle(cTitle) Set the window title using a string parameter. shutdown() Close the application. find(cName) Find an object using the object name remove(nID) Remove an object using the object ID The next table present a group of keywords defined by the class. 55.5. Games Layer 608
648.
Ring Documentation, Release1.16 Keyword Description sprite Create new Sprite object and add it to the game objects. text Create new Text object and add it to the game objects. animate Create new Animate object and add it to the game objects. sound Create new Sound object and add it to the game objects. map Create new Map object and add it to the game objects. 55.7 GameObject Class The next table present the class attributes. Attributes Description enabled True/False determine the state of the object (Active/Not Active) x Number determine the x position of the object. y Number determine the y position of the object. width Number determine the width of the object. height Number determine the height of the object. nIndex Number determine the ID of the object. name String represent the object name. animate True/False to animate the object or not. move True/False to move the object using the keyboard or not. Scaled True/False to scale the object image or not. draw Function to be called when drawing the object. state Function to be called for object animation. keypress Function to be called when a key is pressed. mouse Function to be called when a mouse event happens. The next table present the class methods. Method Description keyboard(oGame,nkey) Check Keyboard Events mouse(oGame,nType,aMouseList) Check Mouse Events rgb(r,g,b) Return new color using the RGB (Red, Green and Blue) Values. 55.8 Sprite Class Parent Class : GameObject Class The next table present the class attributes. Attributes Description image String determine the image file name. point Number determine the limit of automatic movement of the object. direction Number determine the direction of movement. nstep Number determine the increment/decrement during movement. type Number determine the object type in the game (Optional). transparent True/False value determine if the image is transparent. 55.7. GameObject Class 609
649.
Ring Documentation, Release1.16 The next table present the class methods. Method Description Draw(oGame) Draw the object 55.9 Text Class Parent Class : Sprite Class The next table present the class attributes. Attributes Description size Number determine the font size font String determine the font file name text String determine the text to be displayed color Number determine the color The next table present the class methods. Method Description Draw(oGame) Draw the object 55.10 Animate Class Parent Class : Sprite Class The next table present the class attributes. Attributes Description frames Number determine the number of frames frame Number determine the active frame framewidth Number determine the frame width. animate True/False determine using animate or not. scaled True/False determine scaling image or not. The next table present the class methods. Method Description Draw(oGame) Draw the object 55.9. Text Class 610
650.
Ring Documentation, Release1.16 55.11 Sound Class Parent Class : GameObject Class The next table present the class attributes. Attributes Description file String determine the sound file name. once True/False determine to play the file one time or not (loop). The next table present the class methods. Method Description playsound() Play the sound file 55.12 Map Class Parent Class : Sprite Class The next table present the class attributes. Attributes Description aMap List determine the map content using numbers. aImages List determine the image used for each number in the map. BlockWidth Number determine the block width (default = 32). BlockHeight Number determine the block height (default = 32). Animate True/False determine the animation status. The next table present the class methods. Method Description getvalue(x,y) Return the item value in the Map according to the visible part 55.13 Using the Game Engine - Creating the Game Window Load "gameengine.ring" # Give Control to the Game Engine func main # Called by the Game Engine oGame = New Game # Create the Game Object { title = "My First Game" } # Start the Events Loop Note: if you want to define global variables, this must be before load “gameengine.ring” because this instruction will give the control to the game engine. 55.11. Sound Class 611
651.
Ring Documentation, Release1.16 Screen Shot: 55.14 Using the Game Engine - Drawing Text Load "gameengine.ring" # Give Control to the Game Engine func main # Called by the Game Engine oGame = New Game # Create the Game Object { title = "My First Game" text { x = 10 y=50 animate = false size = 20 file = "fonts/pirulen.ttf" text = "game development using ring is very fun!" color = rgb(0,0,0) } } # Start the Events Loop Screen Shot: 55.14. Using the Game Engine - Drawing Text 612
652.
Ring Documentation, Release1.16 55.15 Using the Game Engine - Moving Text Load "gameengine.ring" # Give Control to the Game Engine func main # Called by the Game Engine oGame = New Game # Create the Game Object { title = "My First Game" text { x = 10 y=50 animate = false size = 20 file = "fonts/pirulen.ttf" text = "game development using ring is very fun!" color = rgb(0,0,0) # Color = black } text { x = 10 y=150 # Animation Part ===================================== animate = true # Use Animation (continues on next page) 55.15. Using the Game Engine - Moving Text 613
653.
Ring Documentation, Release1.16 (continued from previous page) direction = GE_DIRECTION_INCVERTICAL # Increase y point = 400 # Continue until y=400 nStep = 3 # Each time y+= 3 #===================================================== size = 20 file = "fonts/pirulen.ttf" text = "welcome to the real world!" color = rgb(0,0,255) # Color = Blue } } # Start the Events Loop Screen Shot: 55.15. Using the Game Engine - Moving Text 614
654.
Ring Documentation, Release1.16 55.16 Using the Game Engine - Playing Sound Load "gameengine.ring" # Give Control to the Game Engine func main # Called by the Game Engine oGame = New Game # Create the Game Object { title = "My First Game" text { x = 10 y=50 animate = false size = 20 file = "fonts/pirulen.ttf" text = "game development using ring is very fun!" color = rgb(0,0,0) # Color = black } text { x = 10 y=150 # Animation Part ====================================== animate = true # Use Animation direction = GE_DIRECTION_INCVERTICAL # Increase y point = 400 # Continue until y=400 nStep = 3 # Each time y+= 3 #====================================================== size = 20 file = "fonts/pirulen.ttf" text = "welcome to the real world!" color = rgb(0,0,255) # Color = Blue } Sound { # Play Sound file = "sound/music1.wav" # Sound File Name } } # Start the Events Loop 55.17 Using the Game Engine - Animation Load "gameengine.ring" # Give Control to the Game Engine func main # Called by the Game Engine oGame = New Game # Create the Game Object { title = "My First Game" animate { file = "images/fire.png" x = 100 y = 200 framewidth = 40 height = 42 nStep = 3 # Used for delay transparent = true state = func oGame,oSelf { # Called by engine each frame (continues on next page) 55.16. Using the Game Engine - Playing Sound 615
655.
Ring Documentation, Release1.16 (continued from previous page) oSelf { nStep-- if nStep = 0 nStep = 3 if frame < 13 # we have 13 frames in animation frame++ # move to next frame else oGame.remove(oself.nIndex) # remove object ok ok } } } } # Start the Events Loop 55.17. Using the Game Engine - Animation 616
656.
Ring Documentation, Release1.16 55.18 Using the Game Engine - Animation and Functions Load "gameengine.ring" # Give Control to the Game Engine func main # Called by the Game Engine oGame = New Game # Create the Game Object { title = "My First Game" for x = 70 to 700 step 50 for y = 70 to 500 step 50 showfire(oGame,x,y) next next } # Start the Events Loop func showfire oGame,nX,nY oGame { animate { file = "images/fire.png" x = nX y = nY framewidth = 40 height = 42 nStep = 3 # Used for delay transparent = true state = func oGame,oSelf { # Called by engine each frame oSelf { nStep-- if nStep = 0 nStep = 3 if frame < 13 # we have 13 frames in animation frame++ # move to next frame else frame=1 ok ok } } } } 55.18. Using the Game Engine - Animation and Functions 617
657.
Ring Documentation, Release1.16 55.19 Using the Game Engine - Sprite - Automatic Movement using Keyboard Load "gameengine.ring" # Give control to the game engine func main # Called by the Game Engine oGame = New Game # Create the Game Object { title = "My First Game" sprite { type = GE_TYPE_PLAYER # Just for our usage x=400 y=400 width=100 height=100 file = "images/player.png" transparent = true Animate=false Move=true # we can move it using keyboard arrows Scaled=true } } # Start the Events Loop 55.19. Using the Game Engine - Sprite - Automatic Movement using Keyboard 618
658.
Ring Documentation, Release1.16 55.20 Using the Game Engine - Sprite - Keypress event Load "gameengine.ring" # Give control to the game engine func main # Called by the Game Engine oGame = New Game # Create the Game Object { title = "My First Game" sprite { type = GE_TYPE_PLAYER # Just for our usage x=400 y=400 width=100 height=100 file = "images/player.png" transparent = true Animate=false Move=false # Custom Movement Scaled=true keypress = func oGame,oSelf,nKey { oSelf { Switch nKey (continues on next page) 55.20. Using the Game Engine - Sprite - Keypress event 619
659.
Ring Documentation, Release1.16 (continued from previous page) on KEY_LEFT x -= 10 on KEY_RIGHT x += 10 on KEY_UP y -= 10 on KEY_DOWN y += 10 off } } } } # Start the Events Loop 55.21 Using the Game Engine - Sprite - Mouse event Load "gameengine.ring" # Give control to the game engine func main # Called by the Game Engine oGame = New Game # Create the Game Object { title = "My First Game" sprite { type = GE_TYPE_PLAYER # Just for our usage x=400 y=400 width=100 height=100 file = "images/player.png" transparent = true Animate=false Move=false # Custom Movement Scaled=true keypress = func oGame,oSelf,nKey { oSelf { Switch nKey on KEY_LEFT x -= 10 on KEY_RIGHT x += 10 on KEY_UP y -= 10 on KEY_DOWN y += 10 off } } mouse = func oGame,oSelf,nType,aMouseList { if nType = GE_MOUSE_UP oSelf { x = aMouseList[GE_MOUSE_X] y = aMouseList[GE_MOUSE_Y] } ok } (continues on next page) 55.21. Using the Game Engine - Sprite - Mouse event 620
660.
Ring Documentation, Release1.16 (continued from previous page) } } # Start the Events Loop 55.22 Using the Game Engine - Sprite - State event Load "gameengine.ring" # Give control to the game engine func main # Called by the Game Engine oGame = New Game # Create the Game Object { title = "My First Game" sprite { type = GE_TYPE_PLAYER # Just for our usage x=400 y=400 width=100 height=100 file = "images/player.png" transparent = true Animate=false Move=false # Custom Movement Scaled=true keypress = func oGame,oSelf,nKey { oSelf { Switch nKey on KEY_LEFT x -= 10 on KEY_RIGHT x += 10 on KEY_UP y -= 10 on KEY_DOWN y += 10 off } } mouse = func oGame,oSelf,nType,aMouseList { if nType = GE_MOUSE_UP oSelf { x = aMouseList[GE_MOUSE_X] y = aMouseList[GE_MOUSE_Y] } ok } state = func oGame,oSelf { oself { if x < 0 x = 0 ok if y < 0 y = 0 ok if x > ogame.width-width x= ogame.width - width ok if y > ogame.height-height y=ogame.height - height ok } } } (continues on next page) 55.22. Using the Game Engine - Sprite - State event 621
661.
Ring Documentation, Release1.16 (continued from previous page) } # Start the Events Loop 55.23 Using the Game Engine - Animate - Events Load "gameengine.ring" # Give control to the game engine func main # Called by the Game Engine oGame = New Game # Create the Game Object { title = "My First Game" animate { file = "images/fbbird.png" x = 10 y = 10 framewidth = 20 scaled = true height = 50 width = 50 nStep = 3 transparent = true state = func oGame,oSelf { oSelf { # Animation nStep-- if nStep = 0 nStep = 3 if frame < 3 frame++ else frame=1 ok ok # Move Down y += 3 if y > 550 y=550 ok } } keypress = func ogame,oself,nKey { oself { if nkey = key_space y -= 55 if y<=0 y=0 ok ok } } (continues on next page) 55.23. Using the Game Engine - Animate - Events 622
662.
Ring Documentation, Release1.16 (continued from previous page) mouse = func ogame,oself,nType,aMouseList { if nType = GE_MOUSE_UP cFunc = oself.keypress call cFunc(oGame,oSelf,Key_Space) ok } } } # Start the Events Loop Screen Shot: 55.23. Using the Game Engine - Animate - Events 623
663.
Ring Documentation, Release1.16 55.24 Using the Game Engine - Map Load "gameengine.ring" # Give control to the game engine func main # Called by the Game Engine oGame = New Game # Create the Game Object { title = "My First Game" Map { blockwidth = 80 blockheight = 80 aMap = [ [0,0,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], [0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], [0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,1,0,0,0], [0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,1,0,0,0,1,0,0,0], [0,0,0,0,0,0,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0] ] aImages = ["images/fbwall.png", "images/fbwallup.png", "images/fbwalldown.png"] state = func oGame,oSelf { oSelf { x -= 3 if x < - 2100 x = 0 ok } } } } # Start the Events Loop Screen Shot: 55.24. Using the Game Engine - Map 624
664.
Ring Documentation, Release1.16 55.25 Using the Game Engine - Map Events Load "gameengine.ring" # Give control to the game engine func main # Called by the Game Engine oGame = New Game # Create the Game Object { title = "My First Game" Map { blockwidth = 80 blockheight = 80 aMap = [ [0,0,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], [0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], [0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,1,0,0,0], [0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,1,0,0,0,1,0,0,0], [0,0,0,0,0,0,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0], (continues on next page) 55.25. Using the Game Engine - Map Events 625
665.
Ring Documentation, Release1.16 (continued from previous page) [0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0] ] aImages = ["images/fbwall.png", "images/fbwallup.png", "images/fbwalldown.png"] state = func oGame,oSelf { oSelf { x -= 3 if x < - 2100 x = 0 ok } } mouse = func ogame,oself,nType,aMouseList { if nType = GE_MOUSE_UP oSelf { mX = aMouseList[GE_MOUSE_X] mY = aMouseList[GE_MOUSE_Y] nValue = GetValue(mX,mY) nRow = GetRow(mX,mY) nCol = GetCol(mX,mY) Switch nValue On 1 aMap[nRow][nCol] = 0 On 2 aMap[nRow][nCol] = 0 On 3 aMap[nRow][nCol] = 0 On 0 aMap[nRow][nCol] = 1 Off } ok } } } # Start the Events Loop Screen Shot: 55.25. Using the Game Engine - Map Events 626
666.
Ring Documentation, Release1.16 55.26 Using the Game Engine - Object and Drawing We can use the Object keyword (defined by the game engine) to create objects from the GameObject class. Example: Load "gameengine.ring" # Give control to the game engine func main # Called by the Game Engine oGame = New Game # Create the Game Object { title = "My First Game" Object { x = 0 y=300 width = 200 height=200 draw = func oGame,oSelf { oSelf { for t = 1 to 210 gl_draw_circle(x,y,t, gl_map_rgb(t*random(255), t*2,t*3),1) next (continues on next page) 55.26. Using the Game Engine - Object and Drawing 627
667.
Ring Documentation, Release1.16 (continued from previous page) } } state = func oGame,oSelf { oSelf { if x <= 800 x+= 3 else x=0 ok } } keypress = func oGame,oSelf,nKey { oSelf { Switch nKey on KEY_LEFT x -= 10 on KEY_RIGHT x += 10 on KEY_UP y -= 10 on KEY_DOWN y += 10 off } } } } # Start the Events Loop Screen Shot: 55.26. Using the Game Engine - Object and Drawing 628
668.
Ring Documentation, Release1.16 Example: Load "gameengine.ring" # Give control to the game engine func main # Called by the Game Engine oGame = New Game # Create the Game Object { title = "My First Game" Object { x = 400 y=300 width = 200 height=200 draw = func oGame,oSelf { oSelf { for t = 1 to 210 gl_draw_rectangle(x+t,y+t, x+t*2,y+t*2, gl_map_rgb(t*random(255), t*2,t*3),1) gl_draw_rectangle(x+t*2,y+t*2, x-t*2,y-t*2, gl_map_rgb(t*random(255), t*2,t*3),1) next } (continues on next page) 55.26. Using the Game Engine - Object and Drawing 629
669.
Ring Documentation, Release1.16 (continued from previous page) } keypress = func oGame,oSelf,nKey { oSelf { Switch nKey on KEY_LEFT x -= 10 on KEY_RIGHT x += 10 on KEY_UP y -= 10 on KEY_DOWN y += 10 off } } } } # Start the Events Loop Screen Shot: 55.26. Using the Game Engine - Object and Drawing 630
670.
Ring Documentation, Release1.16 55.27 Stars Fighter Game The Stars Fighter source code # The Ring Standard Library # Game Engine for 2D Games # 2016, Mahmoud Fayed <msfclipper@yahoo.com> oGameState = NULL load "gameengine.ring" func main oGame = New Game while true oGameState = new GameState oGame { title = "Stars Fighter!" sprite { file = "images/menu1.jpg" x = 0 y=0 width=800 height = 600 scaled = true animate = false keypress = func ogame,oself,nKey { if nkey = key_esc or nKey = GE_AC_BACK ogame.shutdown() but nKey = key_space oGameState.startplay=true ogame.shutdown=true ok } mouse = func ogame,oself,nType,aMouseList { if nType = GE_MOUSE_UP oGameState.startplay=true ogame.shutdown=true ok } } text { animate = false size = 35 file = "fonts/pirulen.ttf" text = "Stars Fighter" x = 10 y=50 } text { animate = false size = 25 file = "fonts/pirulen.ttf" text = "Version 1.0" x = 80 y=100 } text { animate = false (continues on next page) 55.27. Stars Fighter Game 631
671.
Ring Documentation, Release1.16 (continued from previous page) size = 16 file = "fonts/pirulen.ttf" text = "(C) 2016, Mahmoud Fayed" x = 45 y=140 } text { animate = false size = 25 file = "fonts/pirulen.ttf" text = "Press Space to start" x = 190 y=470 } text { animate = false size = 20 file = "fonts/pirulen.ttf" text = "Press Esc to Exit" x = 260 y=510 } Sound { file = "sound/music1.wav" } } if oGameState.startplay oGame.refresh() playstart(oGame) oGame.refresh() ok end func playstart oGame oSound = New Sound { file = "sound/music2.wav" } while true play(oGame) if ogame.shutdown = true and oGameState.value = 0 exit ok ogame.refresh() end oSound.Delete() func play oGame oGame { FPS = 60 FixedFPS = 120 title = "Stars Fighter!" sprite (continues on next page) 55.27. Stars Fighter Game 632
672.
Ring Documentation, Release1.16 (continued from previous page) { file = "images/stars.jpg" x = 0 y = 0 point = -370 direction = ge_direction_dec type = ge_type_background state = func ogame,oself { oself { if x < -350 direction = ge_direction_inc point = 370 but x = 0 and direction = ge_direction_inc direction = ge_direction_dec point = -370 ok } } } sprite { file = "images/player.png" transparent = true type = ge_type_player x = 400 y =400 width=100 height=100 animate=false move=true Scaled=true mouse = func ogame,oself,nType,aMouseList { if not ( aMouseList[GE_MOUSE_X] >= oSelf.x and aMouseList[GE_MOUSE_X] <= oSelf.x+oSelf.width and aMouseList[GE_MOUSE_Y] >= oself.y and aMouseList[GE_MOUSE_Y] <= oSelf.y+oSelf.height ) if nType = GE_MOUSE_DOWN if aMouseList[1] < oSelf.X # left oSelf.X -= 100 else oSelf.X += 100 ok if aMouseList[2] < oSelf.Y # up oSelf.Y -= 100 else oSelf.Y += 100 ok ok else if nType = GE_MOUSE_UP cFunc = oself.keypress call cFunc(oGame,oSelf,Key_Space) ok ok } keypress = func oGame,oself,nkey { if nkey = key_space ogame { sprite { (continues on next page) 55.27. Stars Fighter Game 633
673.
Ring Documentation, Release1.16 (continued from previous page) type = ge_type_fire file = "images/rocket.png" transparent = true x = oself.x + 30 y = oself.y - 30 width = 30 height = 30 point = -30 nstep = 20 direction = ge_direction_decvertical state = func oGame,oSelf { for x in oGame.aObjects if x.type = ge_type_enemy if oself.x >= x.x and oself.y >= x.y and oself.x <= x.x + x.width and oself.y <= x.y + x.height showfire(oGame,x.x+40,x.y+40) ogame.remove(x.nindex) oGameState.score+=10 oGameState.enemies-- checkwin(oGame) exit ok ok next } } } but nkey = key_esc or nKey = GE_AC_BACK ogame.shutdown() ok } state = func oGame,oSelf { oself { if x < 0 x = 0 ok if y < 0 y = 0 ok if x > ogame.screen_w-width x= ogame.screen_w - width ok if y > ogame.screen_h-height y=ogame.screen_h-height ok } } } for g = 1 to oGameState.enemies sprite { type = ge_type_enemy file = "images/enemy.png" transparent = true x = g*random(50) y =g width=100 height=100 animate=true Scaled=true direction = ge_direction_random state = func oGame,oSelf { oself { if x < 0 x = 0 ok if y < 0 y = 0 ok if x > ogame.screen_w-width x= ogame.screen_w - width ok if y > ogame.screen_h-height y=ogame.screen_h-height ok } if random(100) = 1 (continues on next page) 55.27. Stars Fighter Game 634
674.
Ring Documentation, Release1.16 (continued from previous page) ogame { sprite { type = ge_type_fire file = "images/rocket2.png" transparent = true x = oself.x + 30 y = oself.y + oself.height+ 30 width = 30 height = 30 point = ogame.screen_h+30 nstep = 10 direction = ge_direction_incvertical state = func oGame,oSelf { x = oGame.aObjects[oGameState.playerindex] if oself.x >= x.x and oself.y >= x.y and oself.x <= x.x + x.width and oself.y <= x.y + x.height if oGameState.value > 0 oGameState.value-=10 ok ogame.remove(oself.nindex) checkgameover(oGame) ok } } } ok } } next text { size = 30 file = "fonts/pirulen.ttf" text = "Destroy All Enemies!" nstep = 3 color = GE_COLOR_GREEN x = 100 y=50 direction = ge_direction_incvertical point = 500 } text { animate = false point = 400 size = 30 file = "fonts/pirulen.ttf" text = "Score : " + oGameState.score x = 500 y=10 state = func oGame,oSelf { oSelf { text = "Score : " + oGameState.score } } } text { animate = false point = 400 size = 30 file = "fonts/pirulen.ttf" text = "Energy : " + oGameState.value x = 500 y=50 state = func oGame,oSelf { oSelf { text = "Energy : " + oGameState.value } } (continues on next page) 55.27. Stars Fighter Game 635
675.
Ring Documentation, Release1.16 (continued from previous page) } text { animate = false point = 400 size = 30 file = "fonts/pirulen.ttf" text = "Level : " + oGameState.level x = 500 y=90 } } func checkwin ogame if oGameState.gameresult return ok if oGameState.enemies = 0 oGameState.gameresult = true oGame { if oGameState.level < 30 text { point = 400 size = 30 file = "fonts/pirulen.ttf" text = "Level Completed!" nStep = 3 x = 500 y=10 state = func ogame,oself { if oself.y >= 400 ogame.shutdown = true oGameState.level++ oGameState.enemies = oGameState.level oGameState.gameresult = false ok } } else text { point = 400 size = 30 nStep = 3 file = "fonts/pirulen.ttf" text = "You Win !!!" x = 500 y=10 state = func ogame,oself { if oself.y >= 400 ogame.shutdown = true oGameState.value = 0 ok } } ok } ok func checkgameover ogame if oGameState.gameresult return ok if oGameState.value <= 0 oGameState.gameresult = true (continues on next page) 55.27. Stars Fighter Game 636
676.
Ring Documentation, Release1.16 (continued from previous page) oGame { text { point = 400 size = 30 nStep = 3 file = "fonts/pirulen.ttf" text = "Game Over !!!" x = 500 y=10 state = func ogame,oself { if oself.y >= 400 ogame.shutdown = true ok } } } showfire(oGame,oGame.aObjects[oGameState.PlayerIndex].x+40, oGame.aObjects[oGameState.PlayerIndex].y+40) oGame.aObjects[oGameState.PlayerIndex].enabled = false oGame.remove(oGameState.PlayerIndex) ok func showfire oGame,nX,nY oGame { animate { file = "images/fire.png" x = nX y = nY framewidth = 40 height = 42 nStep = 3 transparent = true state = func oGame,oSelf { oSelf { nStep-- if nStep = 0 nStep = 3 if frame < 13 frame++ else frame=1 oGame.remove(oself.nIndex) ok ok } } } } class gamestate score = 0 level = 1 enemies = 1 value = 100 playerindex = 2 gameresult = false (continues on next page) 55.27. Stars Fighter Game 637
677.
Ring Documentation, Release1.16 (continued from previous page) startplay=false Screen Shot: 55.28 Flappy Bird 3000 Game The Flappy Bird 3000 Game source code # The Ring Standard Library # Game Engine for 2D Games # 2016, Mahmoud Fayed <msfclipper@yahoo.com> oGameState = NULL Load "gameengine.ring" func main oGame = New Game (continues on next page) 55.28. Flappy Bird 3000 Game 638
678.
Ring Documentation, Release1.16 (continued from previous page) while true oGameState = New GameState oGame { title = "Flappy Bird 3000" sprite { file = "images/fbback.png" x = 0 y=0 width=800 height = 600 scaled = true animate = false keypress = func ogame,oself,nKey { if nkey = key_esc or nKey = GE_AC_BACK ogame.shutdown() but nKey = key_space oGameState.startplay=true ogame.shutdown=true ok } mouse = func ogame,oself,nType,aMouseList { if nType = GE_MOUSE_UP cFunc = oself.keypress call cFunc(oGame,oSelf,Key_Space) ok } } text { animate = false size = 35 file = "fonts/pirulen.ttf" text = "Flappy Bird 3000" x = 150 y=50 } text { animate = false size = 25 file = "fonts/pirulen.ttf" text = "Version 1.0" x = 280 y=100 } text { animate = false size = 16 file = "fonts/pirulen.ttf" text = "(C) 2016, Mahmoud Fayed" x = 245 y=140 } text { animate = false size = 25 file = "fonts/pirulen.ttf" text = "To Win Get Score = 3000" x = 150 y=270 } text { (continues on next page) 55.28. Flappy Bird 3000 Game 639
679.
Ring Documentation, Release1.16 (continued from previous page) animate = false size = 25 file = "fonts/pirulen.ttf" text = "Press Space to start" x = 190 y=470 } text { animate = false size = 20 file = "fonts/pirulen.ttf" text = "Press Esc to Exit" x = 260 y=510 } animate { file = "images/fbbird.png" x = 200 y = 200 framewidth = 20 scaled = true height = 50 width = 50 nStep = 3 transparent = true animate = true direction = ge_direction_random state = func oGame,oSelf { oSelf { nStep-- if nStep = 0 nStep = 3 if frame < 3 frame++ else frame=1 ok ok if x <= 0 x=0 ok if y <= 0 y=0 ok if x >= 750 x= 750 ok if y > 550 y=550 ok } } } Sound { file = "sound/music2.wav" } } if oGameState.startplay oGame.refresh() playstart(oGame) oGame.refresh() ok end (continues on next page) 55.28. Flappy Bird 3000 Game 640
680.
Ring Documentation, Release1.16 (continued from previous page) func playstart oGame oGame { FPS = 60 FixedFPS = 120 Title = "Flappy Bird 3000" Sprite { file = "images/fbback.png" x = 0 y=0 width=800 height = 600 scaled = true animate = false keypress = func ogame,oself,nKey { if nkey = key_esc or nKey = GE_AC_BACK ogame.shutdown() ok } } Map { blockwidth = 80 blockheight = 80 aMap = [ [0,0,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], [0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], [0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,1,0,0,0], [0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,1,0,0,0,1,0,0,0], [0,0,0,0,0,0,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0] ] newmap(aMap) aImages = ["images/fbwall.png","images/fbwallup.png", "images/fbwalldown.png"] state = func oGame,oSelf { if oGameState.gameresult = false px = oGame.aObjects[3].x py = oGame.aObjects[3].y oSelf { x -= 3 if x < - 2100 x = 0 newmap(aMap) ok nCol = getcol(px,0) if nCol=11 or nCol=15 or nCol=19 or nCol=23 or nCol=27 if nCol != oGameState.lastcol oGameState.lastcol = nCol oGameState.Score += 100 oGame { Sound { once = true file = "sound/sfx_point.wav" } } checkwin(oGame) ok ok } if oSelf.getvalue(px+40,py) != 0 or (continues on next page) 55.28. Flappy Bird 3000 Game 641
681.
Ring Documentation, Release1.16 (continued from previous page) oSelf.getvalue(px+40,py+40) != 0 or oSelf.getvalue(px,py) != 0 or oSelf.getvalue(px,py+40) != 0 oGameState.gameresult = true oGame { text { point = 550 size = 30 nStep = 3 file = "fonts/pirulen.ttf" text = "Game Over !!!" x = 500 y=10 state = func ogame,oself { if oself.y >= 550 ogame.shutdown = true ok if oself.y = 90 ogame { Sound { once = true file = "sound/sfx_die.wav" } } ok } } Sound { once = true file = "sound/sfx_hit.wav" } } ok ok } } animate { file = "images/fbbird.png" x = 10 y = 10 framewidth = 20 scaled = true height = 50 width = 50 nStep = 3 transparent = true state = func oGame,oSelf { oSelf { nStep-- if nStep = 0 nStep = 3 if frame < 3 frame++ else frame=1 ok ok (continues on next page) 55.28. Flappy Bird 3000 Game 642
682.
Ring Documentation, Release1.16 (continued from previous page) } if not oGameState.playerwin oGameState.down -- if oGameState.down = 0 oGameState.down = 3 oself { y += 25 if y > 550 y=550 ok } ok ok } keypress = func ogame,oself,nKey { if oGameState.gameresult = false oself { if nkey = key_space y -= 55 oGameState.down = 60 if y<=0 y=0 ok ok } ok } mouse = func ogame,oself,nType,aMouseList { if nType = GE_MOUSE_UP cFunc = oself.keypress call cFunc(oGame,oSelf,Key_Space) ok } } text { animate = false point = 400 size = 30 file = "fonts/pirulen.ttf" text = "Score : " + oGameState.score x = 500 y=10 state = func oGame,oSelf { oSelf { text = "Score : " + oGameState.score } } } } func newmap aMap aV = [ [1,1,3,0,0,2,1,1], [1,3,0,0,0,2,1,1], [1,1,1,3,0,2,1,1], [1,1,1,3,0,0,0,0], [0,0,0,0,2,1,1,1], [0,0,2,1,1,1,1,1], [0,0,0,2,1,1,1,1], [1,1,1,3,0,2,1,1], (continues on next page) 55.28. Flappy Bird 3000 Game 643
683.
Ring Documentation, Release1.16 (continued from previous page) [1,1,1,1,1,3,0,0], [3,0,0,2,1,1,1,1], [3,0,0,2,3,0,0,2] ] for x = 10 to 24 step 4 aVar = aV[ (random(10)+1) ] for y = 1 to 8 aMap[y][x] = aVar[y] next next func checkwin ogame if oGameState.score = 3000 oGameState.gameresult = true oGameState.playerwin = true oGame { text { point = 400 size = 30 nStep = 3 file = "fonts/pirulen.ttf" text = "You Win !!!" x = 500 y=10 state = func ogame,oself { if oself.y >= 400 ogame.shutdown = true oGameState.value = 0 ok } } } ok Class GameState down = 3 gameresult = false Score = 0 startplay=false lastcol = 0 playerwin = false Screen Shot: 55.28. Flappy Bird 3000 Game 644
684.
Ring Documentation, Release1.16 55.29 Super Man 2016 Game The Super Man 2016 Game source code # The Ring Standard Library # Game Engine for 2D Games # 2016, Mahmoud Fayed <msfclipper@yahoo.com> oGameState = NULL Load "gameengine.ring" func main oGame = New Game while true oGameState = new GameState oGame { (continues on next page) 55.29. Super Man 2016 Game 645
685.
Ring Documentation, Release1.16 (continued from previous page) title = "Super Man 2016" sprite { file = "images/superman.jpg" x = 0 y=0 width=800 height = 600 scaled = true animate = false keypress = func ogame,oself,nKey { if nkey = key_esc or nKey = GE_AC_BACK ogame.shutdown() but nKey = key_space oGameState.startplay=true ogame.shutdown=true ok } mouse = func ogame,oself,nType,aMouseList { if nType = GE_MOUSE_UP oGameState.startplay=true ogame.shutdown=true ok } state = func ogame,oself { oself { if x > -500 x-=1 y-=1 width +=1 height +=4 ok } } } text { animate = false size = 35 file = "fonts/pirulen.ttf" text = "Super Man 2016" x = 20 y=30 } text { animate = false size = 25 file = "fonts/pirulen.ttf" text = "Version 1.0" x = 20 y=80 } text { animate = false size = 16 file = "fonts/pirulen.ttf" text = "(C) 2016, Mahmoud Fayed" x = 20 y=120 } text { animate = false size = 25 file = "fonts/pirulen.ttf" text = "Press Space to start" (continues on next page) 55.29. Super Man 2016 Game 646
686.
Ring Documentation, Release1.16 (continued from previous page) x = 190 y=470 } text { animate = false size = 20 file = "fonts/pirulen.ttf" text = "Press Esc to Exit" x = 260 y=510 } animate { file = "images/superman.png" x = 200 y = 200 framewidth = 68 scaled = true height = 86 width = 60 nStep = 10 transparent = true animate = true direction = ge_direction_random state = func oGame,oSelf { oSelf { nStep-- if nStep = 0 nStep = 10 if frame < 1 frame++ else frame=1 ok ok if x <= 0 x=0 ok if y <= 0 y=0 ok if x >= 750 x= 750 ok if y > 550 y=550 ok } } } Sound { file = "sound/music2.wav" } } if oGameState.startplay oGame.refresh() playstart(oGame) oGame.refresh() ok end func playstart oGame oGame { (continues on next page) 55.29. Super Man 2016 Game 647
687.
Ring Documentation, Release1.16 (continued from previous page) FPS = 60 FixedFPS = 15 Title = "Super Man 2016" Sprite { file = "images/supermancity.jpg" x = 0 y=0 width=800 height = 600 scaled = true animate = false } Map { blockwidth = 80 blockheight = 80 aMap = [ [0,0,0,4,4,4,0,0,0,1,0,0,0,1,4,4,0,1,0,0,0,0,4,4,0,1,4, 4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,0,0,0,1,0,0,0,1,0,3,3,3,5,3,3,3,3,0], [0,0,4,0,4,0,4,0,0,1,0,0,0,3,4,4,4,1,0,0,0,0,4,4,0,1,4, 4,4,0,0,4,4,4,4,4,4,4,4,4,4,4,4,1,4,1,0,0,0,1,0,0,0,1,0,4,4,4,4,4,4,4,4,0], [0,0,0,4,4,4,0,0,0,1,0,0,0,4,4,4,4,1,0,0,0,0,0,0,0,3,4, 4,4,0,0,4,0,0,0,0,0,0,4,2,0,0,4,1,4,1,4,2,4,1,0,2,0,1,0,4,4,4,4,4,4,4,4,0], [0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, 0,0,0,0,4,4,4,4,4,4,4,4,1,0,0,4,1,4,1,4,1,4,1,0,1,0,1,0,2,2,2,2,2,2,2,2,0], [0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, 0,0,0,0,2,0,0,0,0,0,2,0,3,0,0,0,1,4,1,4,1,4,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,1,0,0,0,2,0,0,0,0,0, 0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,4,3,4,1,4,3,0,1,0,3,0,1,0,0,0,0,0,0,0,0], [0,0,2,0,0,2,0,0,2,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0, 0,0,0,0,1,0,0,0,0,0,3,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0], [0,0,1,0,0,1,0,0,1,3,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,0,0, 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0] ] aImages = ["images/smwall.png","images/smwallup.png", "images/smwalldown.png","images/smstar.png", "images/smkey.png","images/smstar2.png"] } sprite { type = ge_type_enemy animate = false file = "images/smhome.png" x = 5000 y = 400 width = 290 height = 200 transparent = true state = func oGame,oSelf { oself { x = 5000 + oGame.aObjects[2].x if x < 0 or x > SCREEN_W return ok } if oGameState.gameresult or oGameState.DoorKey = false return ok if oGame.aObjects[oGameState.playerindex].x > oself.x + 100 and oGame.aObjects[oGameState.playerindex].y > oself.y + 50 oGameState.gameresult = true oGame { sprite { file = "images/smwin.jpg" x=0 y=0 width=800 height=600 scaled = true animate=false (continues on next page) 55.29. Super Man 2016 Game 648
688.
Ring Documentation, Release1.16 (continued from previous page) state = func ogame,oself { oself { x-=5 y-=5 width +=10 height +=10 if x = -300 ogame.shutdown = true ok } } } } ok } } animate { file = "images/superman.png" x = 0 y = 0 framewidth = 60 scaled = true height = 86 width = 60 nStep = 3 transparent = true state = func oGame,oSelf { checkstarskeycol(oGame,oSelf) if not oGameState.playerwin oself { file = "images/superman.png" height = 86 width = 60 for t=1 to 8 if checkwall2(oGame,oSelf,0,5,[2,1]) y += 5 else exit ok next if y > 500 y=500 ok } ok } keypress = func ogame,oself,nKey { if oGameState.gameresult = false oself { if nkey = key_up and checkwall(oGame,oSelf,0,-40) oGameState.value -= 1 checkgameover(oGame) file = "images/supermanup.png" (continues on next page) 55.29. Super Man 2016 Game 649
689.
Ring Documentation, Release1.16 (continued from previous page) height = 123 dotransparent() y -= 40 oGameState.down = 10 if y<=0 y=0 ok but nkey = key_down and checkwall(oGame,oSelf,0,40) file = "images/supermandown.png" dotransparent() y += 40 if y>=500 y=500 ok but nKey = key_right and checkwall(oGame,oSelf,10,0) file = "images/supermanright.png" dotransparent() x += 10 if x >= 440 if oGame.aObjects[2].x > -4500 oGame.aObjects[2].x -= 50 callenemystate(oGame) else if x <= 750 if checkwall(oGame,oSelf,10,0) x += 10 ok else if checkwall(oGame,oSelf,-10,0) x -= 10 ok ok return ok x=400 ok but nKey = key_left and checkwall(oGame,oSelf,-10,0) file = "images/supermanleft.png" dotransparent() x -= 10 if x <= 0 x += 10 if oGame.aObjects[2].x != 0 oGame.aObjects[2].x += 50 callenemystate(oGame) x += 50 ok ok but nkey = key_esc or nKey = GE_AC_BACK ogame.shutdown() ok } ok } mouse = func ogame,oself,nType,aMouseList { if nType = GE_MOUSE_DOWN oGameState.moveplayer = TRUE But nType = GE_MOUSE_UP oGameState.moveplayer = FALSE ok if oGameState.moveplayer = TRUE (continues on next page) 55.29. Super Man 2016 Game 650
690.
Ring Documentation, Release1.16 (continued from previous page) if aMouseList[GE_MOUSE_X] < oSelf.X # left cFunc = oself.keypress call cFunc(oGame,oSelf,Key_left) else cFunc = oself.keypress call cFunc(oGame,oSelf,Key_right) ok if aMouseList[GE_MOUSE_Y] < oSelf.Y # up cFunc = oself.keypress call cFunc(oGame,oSelf,Key_up) else cFunc = oself.keypress call cFunc(oGame,oSelf,Key_down) ok ok } } addenemy(oGame,600) addenemy(oGame,900) addenemy(oGame,1550) addenemy(oGame,2350) addenemy(oGame,3350) addenemy(oGame,3500) addenemy(oGame,3670) addenemy(oGame,3840) text { animate = false point = 400 size = 30 file = "fonts/pirulen.ttf" text = "Score : " + oGameState.score x = 500 y=0 state = func oGame,oSelf { oSelf { text = "Score : " + oGameState.score } } } text { animate = false point = 400 size = 30 file = "fonts/pirulen.ttf" text = "Energy : " + oGameState.value x = 10 y=0 state = func oGame,oSelf { oSelf { text = "Energy : " + oGameState.value } } } } func inlist nValue,aList for x in aList if x = nValue return true ok next (continues on next page) 55.29. Super Man 2016 Game 651
691.
Ring Documentation, Release1.16 (continued from previous page) return false func checkwall oGame,oself,diffx,diffy alist = [1,2,3] return checkwall2(oGame,oself,diffx,diffy,aList) func checkwall2 oGame,oself,diffx,diffy,aList xPos = oSelf.x + diffx yPos = oSelf.y + diffy nValue = oGame.aObjects[2].getvalue(xPos,yPos) nValue = inlist(nValue,aList) nValue = not nValue if nValue = 0 return nValue ok xPos = oSelf.x + diffx yPos = oSelf.y + diffy + oSelf.height nValue = oGame.aObjects[2].getvalue(xPos,yPos) nValue = inlist(nValue,aList) nValue = not nValue if nValue = 0 return nValue ok xPos = oSelf.x + diffx + oSelf.width yPos = oSelf.y + diffy nValue = oGame.aObjects[2].getvalue(xPos,yPos) nValue = inlist(nValue,aList) nValue = not nValue if nValue = 0 return nValue ok xPos = oSelf.x + diffx + oSelf.width yPos = oSelf.y + diffy + oSelf.height nValue = oGame.aObjects[2].getvalue(xPos,yPos) nValue = inlist(nValue,aList) nValue = not nValue if nValue = 0 return nValue ok return nValue func checkopenwall oGame if oGameState.score = 900 oGame.aObjects[2].aMap[3][10] = 3 oGame.aObjects[2].aMap[4][10] = 0 oGame.aObjects[2].aMap[5][10] = 0 oGame.aObjects[2].aMap[6][10] = 0 oGame.aObjects[2].aMap[7][10] = 0 oGame.aObjects[2].aMap[8][10] = 0 but oGameState.score = 1800 oGame.aObjects[2].aMap[3][18] = 3 oGame.aObjects[2].aMap[4][18] = 0 oGame.aObjects[2].aMap[5][18] = 0 oGame.aObjects[2].aMap[6][18] = 0 oGame.aObjects[2].aMap[7][18] = 0 oGame.aObjects[2].aMap[8][18] = 0 but oGameState.score = 5500 oGame.aObjects[2].aMap[1][44] = 0 oGame.aObjects[2].aMap[2][44] = 0 oGame.aObjects[2].aMap[3][44] = 2 ok (continues on next page) 55.29. Super Man 2016 Game 652
692.
Ring Documentation, Release1.16 (continued from previous page) func checkgameover ogame if oGameState.gameresult return ok if oGameState.value <= 0 oGameState.value = 0 oGameState.gameresult = true oGame { text { point = 400 size = 30 nStep = 9 file = "fonts/pirulen.ttf" text = "Game Over !!!" x = 500 y=10 state = func ogame,oself { if oself.y >= 400 ogame.shutdown = true ok } } } showfire(oGame,oGame.aObjects[oGameState.PlayerIndex].x+40, oGame.aObjects[oGameState.PlayerIndex].y+40) oGame.aObjects[oGameState.PlayerIndex].enabled = false oGame.remove(oGameState.PlayerIndex) ok func showfire oGame,nX,nY oGame { animate { file = "images/fire.png" x = nX y = nY framewidth = 40 height = 42 nStep = 3 transparent = true state = func oGame,oSelf { oSelf { nStep-- if nStep = 0 nStep = 3 if frame < 13 frame++ else frame=1 oGame.remove(oself.nIndex) ok ok } } } } func addenemy oGame,xPos (continues on next page) 55.29. Super Man 2016 Game 653
693.
Ring Documentation, Release1.16 (continued from previous page) oGame { lbraceend = false sprite { type = ge_type_enemy file = "images/smenemy.png" transparent = true x = xPos y =10 width=100 height=100 animate=true Scaled=true direction = GE_DIRECTION_NOMOVE temp = xPos state = func oGame,oSelf { oself { x = oSelf.temp + oGame.aObjects[2].x if y < 0 y = 0 ok if y > 100 y=100 ok if x > SCREEN_W or x < 0 return ok } if random(10) = 1 if oGameState.gameresult return ok ogame { sprite { type = ge_type_fire file = "images/smrocket.png" scaled = true transparent = true x = oself.x + 30 y = oself.y + oself.height+ 30 width = 30 height = 30 point = ogame.screen_h+30 nstep = 30 direction = ge_direction_incvertical xvalue = oGame.aObjects[2].x temp = oself.x + 30 - xvalue state = func oGame,oSelf { oself { x = oSelf.temp + oGame.aObjects[2].x } x = oGame.aObjects[oGameState.playerindex] if oself.x >= x.x and oself.y >= x.y and oself.x <= x.x + x.width and oself.y <= x.y + x.height if oGameState.value > 0 oGameState.value-=1000 ok ogame.remove(oself.nindex) checkgameover(oGame) ok } } } ok } } } ogame.lbraceend = true (continues on next page) 55.29. Super Man 2016 Game 654
694.
Ring Documentation, Release1.16 (continued from previous page) func checkstarskey oGame,oSelf,nValue,nRow,nCol switch nValue on 4 oGame.aObjects[2].aMap[nRow][nCol] = 6 oGameState.Score += 100 checkopenwall(oGame) oGame { Sound { once = true file = "sound/sfx_point.wav" } } on 5 oGame.aObjects[2].aMap[nRow][nCol] = 0 oGameState.DoorKey = true oGameState.Score += 500 checkopenwall(oGame) oGame { Sound { once = true file = "sound/sfx_point.wav" } } off func checkstarskeycol oGame,oSelf nValue = oGame.aObjects[2].getvalue(oSelf.x,oSelf.y) nRow = oGame.aObjects[2].getrow(oSelf.x,oSelf.y) nCol = oGame.aObjects[2].getcol(oSelf.x,oSelf.y) checkstarskey(oGame,oSelf,nValue,nRow,nCol) nValue = oGame.aObjects[2].getvalue(oSelf.x+oSelf.width,oSelf.y+oSelf.height) nRow = oGame.aObjects[2].getrow(oSelf.x+oSelf.width,oSelf.y+oSelf.height) nCol = oGame.aObjects[2].getcol(oSelf.x+oSelf.width,oSelf.y+oSelf.height) checkstarskey(oGame,oSelf,nValue,nRow,nCol) nValue = oGame.aObjects[2].getvalue(oSelf.x+oSelf.width,oSelf.y) nRow = oGame.aObjects[2].getrow(oSelf.x+oSelf.width,oSelf.y) nCol = oGame.aObjects[2].getcol(oSelf.x+oSelf.width,oSelf.y) checkstarskey(oGame,oSelf,nValue,nRow,nCol) nValue = oGame.aObjects[2].getvalue(oSelf.x,oSelf.y+oSelf.height) nRow = oGame.aObjects[2].getrow(oSelf.x,oSelf.y+oSelf.height) nCol = oGame.aObjects[2].getcol(oSelf.x,oSelf.y+oSelf.height) checkstarskey(oGame,oSelf,nValue,nRow,nCol) func callenemystate oGame for t in oGame.aObjects t { if type = GE_TYPE_ENEMY call state(oGame,t) ok } next Class GameState down = 3 gameresult = false Score = 0 startplay=false (continues on next page) 55.29. Super Man 2016 Game 655
695.
Ring Documentation, Release1.16 (continued from previous page) lastcol = 0 playerwin = false DoorKey = false playerindex = 4 value = 1000 moveplayer = false Screen Shot: 55.29. Super Man 2016 Game 656
696.
CHAPTER FIFTYSIX BUILDING GAMES FORANDROID In this chapter we will learn about Building RingLibSDL Games for Mobile. So we can create packages (*.apk) for the applications that are developed using Ring Game Engine for 2D Games. 56.1 Download Requirements and Update the Android SDK • The Android SDK Tools https://developer.android.com/studio/index.html • The Android NDK (Tested using android-ndk-r10c) https://developer.android.com/ndk/index.html • Apache Ant v1.8 or later http://ant.apache.org/bindownload.cgi • Java SE Development Kit (JDK) v6 or later http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html • Update the Android SDK to get the API and tools packages required for development Tested using Android 4.4.2 (API 19) • In Windows - Define the next Environment Variables based on your system. (1) JAVA_HOME For Example : C:Program Files (x86)Javajdk1.8.0_05 (2) ANDROID_HOME For Example : B:mahmoudToolsJava-Androidadt-bundle-windows-x86-20140702sdk 657
697.
Ring Documentation, Release1.16 56.2 Project Folder Open the project folder : ring/extensions/android/ringlibsdl/project You can add the source code (*.ring) and Images/Sound Files to the assets folder. You will find the Flappy Bird 3000 Game ready for building. The execution starts from the start.ring file load "game2.ring" 56.2. Project Folder 658
698.
Ring Documentation, Release1.16 56.3 Building the project Move to the ring/extensions/android/ringlibsdl/project folder We can build using the next command (We need to do this for one time only). ndk-build Then we can create the package (*.apk) using the next command. ant debug We can write a batch file for building the project (file: build.bat) rem You will need to modify this batch file based on your environment set JAVA_HOME=C:Program Files (x86)Javajdk1.8.0_05 set ANDROID_HOME=B:mahmoudToolsJavaAndroidadt-bundle-windows-x86-20140702sdk set NDK_ROOT=B:mahmoudToolsJavaAndroidandroid-ndk-r10c set path=%path%;B:mahmoudToolsJavaAndroidandroid-ndk-r10c set path=%path%;B:mahmoudToolsJavaAndroidapache-ant-1.9.4bin ndk-build 56.3. Building the project 659
699.
CHAPTER FIFTYSEVEN DEVELOPING GAMES USINGRINGRAYLIB In this chapter we will learn how to use the RingRayLib extension. 57.1 Introduction RingRayLib is an extension for the RayLib game programming library. Also RayGUI functions are supported by this extension. 57.2 Basic Window load "raylib.ring" screenWidth = 800 screenHeight = 450 InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window") SetTargetFPS(60) while !WindowShouldClose() BeginDrawing() ClearBackground(RED) DrawText("Congrats! You created your first window!", 190, 200, 20, WHITE) EndDrawing() end CloseWindow() Screen Shot: 660
700.
Ring Documentation, Release1.16 57.3 Input Keys load "raylib.ring" screenWidth = 800 screenHeight = 450 InitWindow(screenWidth, screenHeight, "raylib [core] example - keyboard input") ballPosition = Vector2(screenWidth/2, screenHeight/2) SetTargetFPS(60) while !WindowShouldClose() if IsKeyDown(KEY_RIGHT) ballPosition.x += 2 ok if IsKeyDown(KEY_LEFT) ballPosition.x -= 2 ok if IsKeyDown(KEY_UP) ballPosition.y -= 2 ok if IsKeyDown(KEY_DOWN) ballPosition.y += 2 ok BeginDrawing() ClearBackground(RAYWHITE) DrawText("move the ball with arrow keys", 10, 10, 20, DARKGRAY) DrawCircleV(ballPosition, 50, MAROON) EndDrawing() end CloseWindow() Screen Shot: 57.3. Input Keys 661
701.
Ring Documentation, Release1.16 57.4 Input Mouse load "raylib.ring" screenWidth = 800 screenHeight = 450 InitWindow(screenWidth, screenHeight, "raylib [core] example - mouse input") ballPosition = Vector2(100, 100) ballColor = DARKBLUE SetTargetFPS(60) while ! WindowShouldClose() ballPosition = GetMousePosition() if IsMouseButtonPressed(MOUSE_LEFT_BUTTON) ballColor = MAROON but IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON) ballColor = LIME but IsMouseButtonPressed(MOUSE_RIGHT_BUTTON) ballColor = DARKBLUE ok BeginDrawing() ClearBackground(BLACK) DrawCircleV(ballPosition, 40, ballColor) (continues on next page) 57.4. Input Mouse 662
702.
Ring Documentation, Release1.16 (continued from previous page) DrawText("move ball with mouse and click mouse button to change color ˓ →", 10, 10, 20, YELLOW) EndDrawing() end CloseWindow() Screen Shot: 57.5 3D Camera load "raylib.ring" screenWidth = 800 screenHeight = 450 InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera mode") camera = Camera3D( 0, 10, 10, // Camera position 0, 0, 0 , // Camera looking at point 0, 1, 0, // Camera up vector (rotation towards target) 45, // Camera field-of-view Y CAMERA_PERSPECTIVE) // Camera mode type cubePosition = Vector3(0, 0, 0) (continues on next page) 57.5. 3D Camera 663
703.
Ring Documentation, Release1.16 (continued from previous page) SetTargetFPS(60) while !WindowShouldClose() BeginDrawing() ClearBackground(RAYWHITE) BeginMode3D(camera) DrawCube(cubePosition, 2, 2, 2, RED) DrawCubeWires(cubePosition, 2, 2, 2, MAROON) DrawGrid(10, 1) EndMode3D() DrawText("Welcome to the third dimension!", 10, 40, 20, DARKGRAY) DrawFPS(10, 10) EndDrawing() end CloseWindow() Screen Shot: 57.5. 3D Camera 664
704.
Ring Documentation, Release1.16 57.6 3D Camera Free load "raylib.ring" screenWidth = 800 screenHeight = 450 InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera free") camera = Camera3D( 10, 10, 10, // Camera position 0, 0, 0 , // Camera looking at point 0, 1, 0, // Camera up vector (rotation towards target) 45, // Camera field-of-view Y CAMERA_PERSPECTIVE) // Camera mode type cubePosition = Vector3(0, 0, 0) SetCameraMode(camera, CAMERA_FREE) // Set a free camera mode SetTargetFPS(60) while !WindowShouldClose() UpdateCamera(camera) if IsKeyDown("Z") camera.target = Vector3( 0, 0, 0) ok BeginDrawing() ClearBackground(RAYWHITE) BeginMode3D(camera) DrawCube(cubePosition, 2, 2, 2, RED) DrawCubeWires(cubePosition, 2, 2, 2, MAROON) DrawGrid(10, 1) EndMode3D() DrawRectangle( 10, 10, 320, 133, Fade(SKYBLUE, 0.5)) DrawRectangleLines( 10, 10, 320, 133, BLUE) DrawText("Free camera default controls:", 20, 20, 10, BLACK) DrawText("- Mouse Wheel to Zoom in-out", 40, 40, 10, DARKGRAY) DrawText("- Mouse Wheel Pressed to Pan", 40, 60, 10, DARKGRAY) DrawText("- Alt + Mouse Wheel Pressed to Rotate", 40, 80, 10, ˓ →DARKGRAY) DrawText("- Alt + Ctrl + Mouse Wheel Pressed for Smooth Zoom", 40, 100, 10, DARKGRAY) DrawText("- Z to zoom to (0, 0, 0)", 40, 120, 10, DARKGRAY) EndDrawing() end CloseWindow() 57.6. 3D Camera Free 665
705.
Ring Documentation, Release1.16 Screen Shot: 57.7 Mouse Wheel load "raylib.ring" screenWidth = 800 screenHeight = 450 InitWindow(screenWidth, screenHeight, "raylib [core] example - input mouse wheel") boxPositionY = screenHeight/2 - 40 scrollSpeed = 4 SetTargetFPS(60) while !WindowShouldClose() boxPositionY -= (GetMouseWheelMove()*scrollSpeed) BeginDrawing() ClearBackground(RAYWHITE) DrawRectangle(screenWidth/2 - 40, boxPositionY, 80, 80, MAROON) DrawText("Use mouse wheel to move the cube up and down!", 10, 10, 20, GRAY) DrawText("Box position Y: "+boxPositionY, 10, 40, 20, LIGHTGRAY) EndDrawing() (continues on next page) 57.7. Mouse Wheel 666
706.
Ring Documentation, Release1.16 (continued from previous page) end CloseWindow() Screen Shot: 57.8 Input Multi-touch load "raylib.ring" screenWidth = 800 screenHeight = 450 InitWindow(screenWidth, screenHeight, "raylib [core] example - input multitouch") ballPosition = Vector2(-100, -100) ballColor = BEIGE touchCounter = 0 touchPosition = vector2(0,0) MAX_TOUCH_POINTS = 5 SetTargetFPS(60) while !WindowShouldClose() ballPosition = GetMousePosition() (continues on next page) 57.8. Input Multi-touch 667
707.
Ring Documentation, Release1.16 (continued from previous page) ballColor = BEIGE if IsMouseButtonDown(MOUSE_LEFT_BUTTON) ballColor = MAROON ok if IsMouseButtonDown(MOUSE_MIDDLE_BUTTON) ballColor = LIME ok if IsMouseButtonDown(MOUSE_RIGHT_BUTTON) ballColor = DARKBLUE ok if IsMouseButtonPressed(MOUSE_LEFT_BUTTON) touchCounter = 10 ok if IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON) touchCounter = 10 ok if IsMouseButtonPressed(MOUSE_RIGHT_BUTTON) touchCounter = 10 ok if touchCounter > 0 touchCounter-- ok BeginDrawing() ClearBackground(RAYWHITE) for i = 0 to MAX_TOUCH_POINTS-1 touchPosition = GetTouchPosition(i) if touchPosition.x >= 0 && touchPosition.y >= 0 DrawCircleV(touchPosition, 34, ORANGE) DrawText(""+ i, touchPosition.x - 10, touchPosition.y - 70, 40, BLACK) ok next DrawCircleV(ballPosition, 30 + (touchCounter*3), ballColor) DrawText("move ball with mouse and click mouse button to change color", 10, 10, 20, DARKGRAY) DrawText("touch the screen at multiple locations to get multiple balls", 10, 30, 20, DARKGRAY) EndDrawing() end CloseWindow() Screen Shot: 57.8. Input Multi-touch 668
708.
Ring Documentation, Release1.16 57.9 Camera First Person load "raylib.ring" MAX_COLUMNS = 20 screenWidth = 800 screenHeight = 450 InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera first person ˓ →") camera = Camera3d( 4, 2, 4, 0, 1, 0, 0, 1, 0, 60, CAMERA_PERSPECTIVE ) heights = list(MAX_COLUMNS) positions = list(MAX_COLUMNS) for item in positions item = vector3(0,0,0) next colors = list(MAX_COLUMNS) for item in colors item = BLACK next for i = 1 to MAX_COLUMNS heights[i] = GetRandomValue(1, 12) positions[i] = Vector3(GetRandomValue(-15, 15), (continues on next page) 57.9. Camera First Person 669
709.
Ring Documentation, Release1.16 (continued from previous page) heights[i]/2, GetRandomValue(-15, 15) ) colors[i] = RAYLibColor(GetRandomValue(20, 255), GetRandomValue(10, 55), 30, 255 ) next SetCameraMode(camera, CAMERA_FIRST_PERSON) SetTargetFPS(60) while !WindowShouldClose() UpdateCamera(camera) BeginDrawing() ClearBackground(RAYWHITE) BeginMode3D(camera) DrawPlane(Vector3( 0, 0, 0 ), Vector2(32, 32 ), LIGHTGRAY) // Draw ground DrawCube(Vector3( -16, 2.5, 0 ), 1, 5, 32, BLUE) // Draw a blue wall DrawCube(Vector3( 16, 2.5, 0 ), 1, 5, 32, LIME) // Draw a green wall DrawCube(Vector3( 0, 2.5, 16 ), 32, 5, 1, GOLD) // Draw a yellow wall for i = 1 to MAX_COLUMNS DrawCube(positions[i], 2, heights[i], 2, colors[i]) DrawCubeWires(positions[i], 2, heights[i], 2, MAROON) next EndMode3D() DrawRectangle( 10, 10, 220, 70, Fade(SKYBLUE, 0.5f)) DrawRectangleLines( 10, 10, 220, 70, BLUE) DrawText("First person camera default controls:", 20, 20, 10, BLACK) DrawText("- Move with keys: W, A, S, D", 40, 40, 10, DARKGRAY) DrawText("- Mouse move to look around", 40, 60, 10, DARKGRAY) EndDrawing() end CloseWindow() Screen Shot: 57.9. Camera First Person 670
710.
Ring Documentation, Release1.16 57.10 3D Picking load "raylib.ring" screenWidth = 800 screenHeight = 450 InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d picking") camera = Camera3D( 10, 10, 10, 0, 0, 0 , 0, 1, 0 , 45, CAMERA_PERSPECTIVE ) cubePosition = Vector3( 0, 1, 0 ) cubeSize = Vector3( 2, 2, 2 ) ray = Ray(0,0,0,0,0,0) collision = false SetCameraMode(camera, CAMERA_FREE) SetTargetFPS(60) while !WindowShouldClose() (continues on next page) 57.10. 3D Picking 671
711.
Ring Documentation, Release1.16 (continued from previous page) UpdateCamera(camera) if IsMouseButtonPressed(MOUSE_LEFT_BUTTON) if !collision ray = GetMouseRay(GetMousePosition(), camera) collision = CheckCollisionRayBox(ray, BoundingBox( cubePosition.x - cubeSize.x/2, cubePosition.y - cubeSize.y/2, cubePosition.z - cubeSize.z/2, cubePosition.x + cubeSize.x/2, cubePosition.y + cubeSize.y/2, cubePosition.z + cubeSize.z/2 ) ) else collision = false ok ok BeginDrawing() ClearBackground(RAYWHITE) BeginMode3D(camera) if collision DrawCube(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, RED) DrawCubeWires(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, ˓ →MAROON) DrawCubeWires(cubePosition, cubeSize.x + 0.2f, cubeSize.y + 0.2f, cubeSize.z + 0.2f, GREEN) else DrawCube(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, GRAY) DrawCubeWires(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, ˓ →DARKGRAY) ok DrawRay(ray, MAROON) DrawGrid(10, 1) EndMode3D() DrawText("Try selecting the box with mouse!", 240, 10, 20, DARKGRAY) if collision DrawText("BOX SELECTED", (screenWidth - MeasureText("BOX SELECTED", 30)) / 2, screenHeight * 0.1f, 30, GREEN) ok DrawFPS(10, 10) EndDrawing() end CloseWindow() Screen Shot: 57.10. 3D Picking 672
712.
Ring Documentation, Release1.16 57.11 Full Screen load "raylib.ring" screenWidth = 1024 screenHeight = 768 InitWindow(screenWidth, screenHeight, "Full Screen") ToggleFullScreen() SetTargetFPS(60) while !WindowShouldClose() BeginDrawing() ClearBackground(DARKBLUE) DrawText("Count from 1 to 10", 190, 200, 20, Yellow) for t = 1 to 10 DrawText("Number: " + t, 190, 200+(30*t), 20, WHITE) next EndDrawing() end CloseWindow() Screen Shot: 57.11. Full Screen 673
713.
Ring Documentation, Release1.16 57.12 Two Cubes load "raylib.ring" screenWidth = 800 screenHeight = 450 InitWindow(screenWidth, screenHeight, "raylib [core] example - Two Cubes") camera = Camera3D( 10, 10, 10, 0, 0, 0 , 0, 1, 0 , 45, CAMERA_PERSPECTIVE ) cubePosition1 = Vector3( 0, 1, 4 ) cubePosition2 = Vector3( 0, 1, -4 ) cubeSize = Vector3( 2, 2, 2 ) ray = Ray(0,0,0,0,0,0) collision1 = false (continues on next page) 57.12. Two Cubes 674
714.
Ring Documentation, Release1.16 (continued from previous page) collision2 = false SetCameraMode(camera, CAMERA_FREE) SetTargetFPS(60) while !WindowShouldClose() UpdateCamera(camera) if IsMouseButtonPressed(MOUSE_LEFT_BUTTON) if !collision1 ray = GetMouseRay(GetMousePosition(), camera) collision1 = CheckCollisionRayBox(ray, BoundingBox( cubePosition1.x - cubeSize.x/2, cubePosition1.y - cubeSize.y/2, cubePosition1.z - cubeSize.z/2, cubePosition1.x + cubeSize.x/2, cubePosition1.y + cubeSize.y/2, cubePosition1.z + cubeSize.z/2 ) ) else collision1 = false ok if !collision2 ray = GetMouseRay(GetMousePosition(), camera) collision2 = CheckCollisionRayBox(ray, BoundingBox( cubePosition2.x - cubeSize.x/2, cubePosition2.y - cubeSize.y/2, cubePosition2.z - cubeSize.z/2, cubePosition2.x + cubeSize.x/2, cubePosition2.y + cubeSize.y/2, cubePosition2.z + cubeSize.z/2 ) ) else collision2 = false ok ok BeginDrawing() ClearBackground(RAYWHITE) BeginMode3D(camera) if collision1 DrawCube(cubePosition1, cubeSize.x, cubeSize.y, cubeSize.z, RED) DrawCubeWires(cubePosition1, cubeSize.x, cubeSize.y, cubeSize.z, MAROON) DrawCubeWires(cubePosition1, cubeSize.x + 0.2f, cubeSize.y + 0.2f, cubeSize.z + 0.2f, GREEN) collision1 = true else DrawCube(cubePosition1, cubeSize.x, (continues on next page) 57.12. Two Cubes 675
715.
Ring Documentation, Release1.16 (continued from previous page) cubeSize.y, cubeSize.z, GRAY) DrawCubeWires(cubePosition1, cubeSize.x, cubeSize.y, cubeSize.z, DARKGRAY) collision1 = false ok if collision2 DrawCube(cubePosition2, cubeSize.x, cubeSize.y, cubeSize.z, RED) DrawCubeWires(cubePosition2, cubeSize.x, cubeSize.y, cubeSize.z, MAROON) DrawCubeWires(cubePosition2, cubeSize.x + 0.2f, cubeSize.y + 0.2f, cubeSize.z + 0.2f, GREEN) collision2 = true else DrawCube(cubePosition2, cubeSize.x, cubeSize.y, cubeSize.z, GRAY) DrawCubeWires(cubePosition2, cubeSize.x, cubeSize.y, cubeSize.z, DARKGRAY) collision2 = false ok DrawRay(ray, MAROON) DrawGrid(10, 1) EndMode3D() DrawText("Try selecting the box with mouse!", 240, 10, 20, DARKGRAY) if collision1 or collision2 DrawText("BOX SELECTED", (screenWidth - MeasureText("BOX SELECTED", 30)) / 2, screenHeight * 0.1f, 30, GREEN) ok DrawFPS(10, 10) EndDrawing() end CloseWindow() Screen Shot: 57.12. Two Cubes 676
Ring Documentation, Release1.16 57.15 Bezier Lines load "raylib.ring" screenWidth = 800 screenHeight = 450 SetConfigFlags(FLAG_MSAA_4X_HINT) InitWindow(screenWidth, screenHeight, "raylib [shapes] example - cubic-bezier lines") start = Vector2(0,0) endvec = Vector2(screenWidth,screenHeight) SetTargetFPS(60) while (!WindowShouldClose()) if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) start = GetMousePosition() else (IsMouseButtonDown(MOUSE_RIGHT_BUTTON)) endvec = GetMousePosition() ok BeginDrawing() ClearBackground(RAYWHITE) DrawText("USE MOUSE LEFT-RIGHT CLICK to DEFINE LINE START and END POINTS", 15, 20, 20, GRAY) DrawLineBezier(start, endvec, 2.0, RED) EndDrawing() end CloseWindow() Screen Shot: 57.15. Bezier Lines 681
721.
Ring Documentation, Release1.16 57.16 Collision Area load "raylib.ring" screenWidth = 800 screenHeight = 450 InitWindow(screenWidth, screenHeight, "raylib [shapes] example - collision area") // Box A: Moving box boxA = Rectangle( 10, GetScreenHeight()/2 - 50, 200, 100 ) boxASpeedX = 4 // Box B: Mouse moved box boxB = Rectangle( GetScreenWidth()/2 - 30, GetScreenHeight()/2 - 30, 60, 60 ) boxCollision = GetCollisionRec(boxA, boxB) boxCollision = Rectangle( 0,0,0,0 ) // Collision rectangle screenUpperLimit = 40 // Top menu limits pause = false // Movement pause collision = false // Collision detection SetTargetFPS(60) while !WindowShouldClose() (continues on next page) 57.16. Collision Area 682
722.
Ring Documentation, Release1.16 (continued from previous page) // Move box if not paused if (not pause) boxA.x += boxASpeedX ok // Bounce box on x screen limits if (((boxA.x + boxA.width) >= GetScreenWidth()) or (boxA.x <= 0)) boxASpeedX = boxASpeedX*(-1) ok // Update player-controlled-box (box02) boxB.x = GetMouseX() - boxB.width/2 boxB.y = GetMouseY() - boxB.height/2 // Make sure Box B does not go out of move area limits if ((boxB.x + boxB.width) >= GetScreenWidth()) boxB.x = GetScreenWidth() - boxB.width else (boxB.x <= 0) boxB.x = 0 ok if ((boxB.y + boxB.height) >= GetScreenHeight()) boxB.y = GetScreenHeight() - boxB.height else (boxB.y <= screenUpperLimit) boxB.y = screenUpperLimit ok // Check boxes collision collision = CheckCollisionRecs(boxA, boxB) // Get collision rectangle (only on collision) if (collision) boxCollision = GetCollisionRec(boxA, boxB) ok // Pause Box A movement if (IsKeyPressed(KEY_SPACE)) pause = not pause ok BeginDrawing() ClearBackground(RAYWHITE) if collision = true color = RED else color = BLACK ok DrawRectangle(0, 0, screenWidth, screenUpperLimit, color) DrawRectangleRec(boxA, GOLD) boxB.x = GetMouseX() - boxB.width/2 boxB.y = GetMouseY() - boxB.height/2 collision = CheckCollisionRecs(boxA, boxB) DrawRectangleRec(boxB, BLUE) boxCollision = GetCollisionRec(boxA, boxB) if (collision) = true // Draw collision area DrawRectangleRec(boxCollision, LIME) // Draw collision message DrawText("COLLISION!", GetScreenWidth()/2 - MeasureText("COLLISION!", 20)/2, screenUpperLimit/2 - 10, 20, BLACK) (continues on next page) 57.16. Collision Area 683
723.
Ring Documentation, Release1.16 (continued from previous page) // Draw collision area DrawText("Collision Area: " + string(boxCollision.width*boxCollision.height), GetScreenWidth()/2 - 100, screenUpperLimit + 10, 20, BLACK) ok DrawFPS(10, 10) EndDrawing() end CloseWindow() Screen Shot: 57.17 Following Eyes load "raylib.ring" screenWidth = 800 screenHeight = 450 InitWindow(screenWidth, screenHeight, "raylib [shapes] example - following eyes") scleraLeftPosition = Vector2( GetScreenWidth()/2 - 100, GetScreenHeight()/2 ) (continues on next page) 57.17. Following Eyes 684
724.
Ring Documentation, Release1.16 (continued from previous page) scleraRightPosition = Vector2( GetScreenWidth()/2 + 100, GetScreenHeight()/2 ) scleraRadius = 80 irisLeftPosition = Vector2( GetScreenWidth()/2 - 100, GetScreenHeight()/2 ) irisRightPosition = Vector2( GetScreenWidth()/2 + 100, GetScreenHeight()/2 ) irisRadius = 24 angle = 0.0 dx = 0.0 dy = 0.0 dxx = 0.0 dyy = 0.0 SetTargetFPS(60) while !WindowShouldClose() irisLeftPosition = GetMousePosition() irisRightPosition = GetMousePosition() // Check not inside the left eye sclera if !CheckCollisionPointCircle(irisLeftPosition, scleraLeftPosition, scleraRadius - 20) dx = irisLeftPosition.x - scleraLeftPosition.x dy = irisLeftPosition.y - scleraLeftPosition.y angle = atan2(dy, dx) dxx = (scleraRadius - irisRadius)*cos(angle) dyy = (scleraRadius - irisRadius)*sin(angle) irisLeftPosition.x = scleraLeftPosition.x + dxx irisLeftPosition.y = scleraLeftPosition.y + dyy ok // Check not inside the right eye sclera if !CheckCollisionPointCircle(irisRightPosition, scleraRightPosition, scleraRadius - 20) dx = irisRightPosition.x - scleraRightPosition.x dy = irisRightPosition.y - scleraRightPosition.y angle = atan2(dy, dx) dxx = (scleraRadius - irisRadius)*cos(angle) dyy = (scleraRadius - irisRadius)*sin(angle) irisRightPosition.x = scleraRightPosition.x + dxx irisRightPosition.y = scleraRightPosition.y + dyy ok BeginDrawing() ClearBackground(RAYWHITE) DrawCircleV(scleraLeftPosition, scleraRadius, LIGHTGRAY) DrawCircleV(irisLeftPosition, irisRadius, BROWN) DrawCircleV(irisLeftPosition, 10, BLACK) DrawCircleV(scleraRightPosition, scleraRadius, LIGHTGRAY) DrawCircleV(irisRightPosition, irisRadius, DARKGREEN) (continues on next page) 57.17. Following Eyes 685
725.
Ring Documentation, Release1.16 (continued from previous page) DrawCircleV(irisRightPosition, 10, BLACK) DrawFPS(10, 10) EndDrawing() end CloseWindow() Screen Shot: 57.18 Colors Palette load "raylib.ring" MAX_COLORS_COUNT = 21 // Number of colors available screenWidth = 800 screenHeight = 450 colors = list(MAX_COLORS_COUNT) colorNames = list(MAX_COLORS_COUNT) colorsRecs = list(MAX_COLORS_COUNT) colorState = list(MAX_COLORS_COUNT) InitWindow(screenWidth, screenHeight, "raylib [shapes] example - colors palette") colors = [ (continues on next page) 57.18. Colors Palette 686
726.
Ring Documentation, Release1.16 (continued from previous page) DARKGRAY, MAROON, ORANGE, DARKGREEN, DARKBLUE, DARKPURPLE, DARKBROWN, GRAY, RED, GOLD, LIME, BLUE, VIOLET, BROWN, LIGHTGRAY, PINK, YELLOW, GREEN, SKYBLUE, PURPLE, BEIGE ] colorNames = [ "DARKGRAY", "MAROON", "ORANGE", "DARKGREEN", "DARKBLUE", "DARKPURPLE", "DARKBROWN", "GRAY", "RED", "GOLD", "LIME", "BLUE", "VIOLET", "BROWN", "LIGHTGRAY", "PINK", "YELLOW", "GREEN", "SKYBLUE", "PURPLE", "BEIGE" ] for i = 1 to MAX_COLORS_COUNT colorsRecs[i] = new Rectangle(0,0,0,0) next for i = 1 to MAX_COLORS_COUNT colorState[i] = 0 next // Fills colorsRecs data (for every rectangle) for i = 1 to MAX_COLORS_COUNT colorsRecs[i].x = 20 + 100*((i-1)%7) + 10*((i-1)%7) colorsRecs[i].y = 80 + 100*floor((i-1)/7) + 10*floor((i-1)/7) colorsRecs[i].width = 100 colorsRecs[i].height = 100 next mousePoint = Vector2( 0.0, 0.0 ) SetTargetFPS(60) // Main game loop while !WindowShouldClose() mousePoint = GetMousePosition() for i = 1 to MAX_COLORS_COUNT if (CheckCollisionPointRec(mousePoint, colorsRecs[i])) colorState[i] = 1 else colorState[i] = 0 ok next BeginDrawing() ClearBackground(RAYWHITE) DrawText("raylib colors palette", 28, 42, 20, BLACK) DrawText("press SPACE to see all colors", GetScreenWidth() - 180, GetScreenHeight() - 40, 10, GRAY) for i = 1 to MAX_COLORS_COUNT // Draw all rectangles if colorState[i] cstate = 0.6 else cstate = 1.0 ok (continues on next page) 57.18. Colors Palette 687
727.
Ring Documentation, Release1.16 (continued from previous page) DrawRectangleRec(colorsRecs[i], Fade(colors[i], cstate)) if (IsKeyDown(KEY_SPACE) || colorState[i]) DrawRectangle(colorsRecs[i].x, colorsRecs[i].y + colorsRecs[i].height - 26, colorsRecs[i].width, 20, BLACK) DrawRectangleLinesEx(colorsRecs[i], 6, Fade(BLACK, 0.3f)) DrawText(colorNames[i], colorsRecs[i].x + colorsRecs[i].width - MeasureText(colorNames[i], 10) - 12, colorsRecs[i].y + colorsRecs[i].height - 20, 10, colors[i]) ok next EndDrawing() end CloseWindow() Screen Shot: 57.18. Colors Palette 688
728.
Ring Documentation, Release1.16 57.19 Rectangle Scaling load "raylib.ring" MOUSE_SCALE_MARK_SIZE = 12 screenWidth = 800 screenHeight = 450 InitWindow(screenWidth, screenHeight, "raylib [shapes] example - rectangle scaling mouse") rec = Rectangle( 100, 100, 200, 80 ) mousePosition = Vector2( 0,0 ) mouseScaleReady = false mouseScaleMode = false SetTargetFPS(60) while !WindowShouldClose() mousePosition = GetMousePosition() if (CheckCollisionPointRec(mousePosition, rec) and CheckCollisionPointRec(mousePosition, Rectangle(rec.x + rec.width - MOUSE_SCALE_MARK_SIZE, rec.y + rec.height - MOUSE_SCALE_MARK_SIZE, MOUSE_SCALE_MARK_SIZE, MOUSE_SCALE_MARK_SIZE ))) mouseScaleReady = true if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) mouseScaleMode = true ok else mouseScaleReady = false ok if (mouseScaleMode) mouseScaleReady = true rec.width = (mousePosition.x - rec.x) rec.height = (mousePosition.y - rec.y) if (rec.width < MOUSE_SCALE_MARK_SIZE) rec.width = MOUSE_SCALE_MARK_SIZE ok if (rec.height < MOUSE_SCALE_MARK_SIZE) rec.height = MOUSE_SCALE_MARK_SIZE ok if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) mouseScaleMode = false ok ok BeginDrawing() ClearBackground(RAYWHITE) DrawText("Scale rectangle dragging from bottom-right corner!", 10, 10, 20, GRAY) (continues on next page) 57.19. Rectangle Scaling 689
Ring Documentation, Release1.16 57.20 Music Playing load "raylib.ring" screenWidth = 800 screenHeight = 450 InitWindow(screenWidth, screenHeight, "raylib [audio] example - music playing (streaming)") InitAudioDevice() music = LoadMusicStream("guitar_noodling.ogg") PlayMusicStream(music) timePlayed = 0.0 pause = false SetTargetFPS(60) while !WindowShouldClose() UpdateMusicStream(music) if IsKeyPressed(KEY_SPACE) StopMusicStream(music) PlayMusicStream(music) ok if IsKeyPressed(KEY_P) pause = !pause if pause PauseMusicStream(music) else ResumeMusicStream(music) ok ok timePlayed = GetMusicTimePlayed(music) / GetMusicTimeLength(music) *400 if timePlayed > 400 StopMusicStream(music) ok BeginDrawing() ClearBackground(RAYWHITE) DrawText("MUSIC SHOULD BE PLAYING!", 255, 150, 20, LIGHTGRAY) DrawRectangle(200, 200, 400, 12, LIGHTGRAY) DrawRectangle(200, 200, timePlayed, 12, MAROON) DrawRectangleLines(200, 200, 400, 12, GRAY) (continues on next page) 57.20. Music Playing 691
731.
Ring Documentation, Release1.16 (continued from previous page) DrawText("PRESS SPACE TO RESTART MUSIC", 215, 250, 20, LIGHTGRAY) DrawText("PRESS P TO PAUSE/RESUME MUSIC", 208, 280, 20, LIGHTGRAY) EndDrawing() end UnloadMusicStream(music) CloseAudioDevice() CloseWindow() Screen Shot: 57.21 Sound Loading load "raylib.ring" screenWidth = 800 screenHeight = 450 InitWindow(screenWidth, screenHeight, "raylib [audio] example - sound loading and playing") InitAudioDevice() fxWav = LoadSound("sound.wav") (continues on next page) 57.21. Sound Loading 692
732.
Ring Documentation, Release1.16 (continued from previous page) fxOgg = LoadSound("tanatana.ogg") SetTargetFPS(60) while !WindowShouldClose() if IsKeyPressed(KEY_SPACE) PlaySound(fxWav) ok if IsKeyPressed(KEY_ENTER) PlaySound(fxOgg) ok BeginDrawing() ClearBackground(RAYWHITE) DrawText("Press SPACE to PLAY the WAV sound!", 200, 180, 20, ˓ →LIGHTGRAY) DrawText("Press ENTER to PLAY the OGG sound!", 200, 220, 20, ˓ →LIGHTGRAY) EndDrawing() end UnloadSound(fxWav) UnloadSound(fxOgg) CloseAudioDevice() CloseWindow() Screen Shot: 57.21. Sound Loading 693
733.
Ring Documentation, Release1.16 57.22 Image Drawing load "raylib.ring" screenWidth = 800 screenHeight = 450 InitWindow(screenWidth, screenHeight, "raylib [textures] example - image drawing") cat = LoadImage("cat.png") ImageCrop( cat, Rectangle( 100, 10, 280, 380 )) ImageFlipHorizontal( cat) ImageResize( cat, 150, 200) parrots = LoadImage("parrots.png") ImageDraw( parrots, cat, Rectangle( 0, 0, cat.width, cat.height ), Rectangle( 30, 40, cat.width*1.5, cat.height*1.5 )) ImageCrop( parrots, Rectangle( 0, 50, parrots.width, parrots.height - 100 )) UnloadImage(cat) font = LoadFont("custom_jupiter_crash.png") ImageDrawTextEx(parrots, Vector2( 300, 230 ), font, "PARROTS & CAT", font.baseSize, -2, WHITE) UnloadFont(font); texture = LoadTextureFromImage(parrots) UnloadImage(parrots) SetTargetFPS(60) while !WindowShouldClose() BeginDrawing() ClearBackground(RAYWHITE) DrawTexture(texture, screenWidth/2 - texture.width/2, screenHeight/2 - texture.height/2 - 40, WHITE) DrawRectangleLines(screenWidth/2 - texture.width/2, screenHeight/2 - texture.height/2 - 40, texture.width, texture.height, DARKGRAY) DrawText("We are drawing only one texture from various images composed!", 240, 350, 10, DARKGRAY) DrawText("Source images have been cropped, scaled,"+ " flipped and copied one over the other.", 190, 370, 10, DARKGRAY) EndDrawing() end UnloadTexture(texture) (continues on next page) 57.22. Image Drawing 694
Ring Documentation, Release1.16 (continued from previous page) bool IsGamepadAvailable(int gamepad) bool IsGamepadName(int gamepad, const char *name) const char *GetGamepadName(int gamepad) bool IsGamepadButtonPressed(int gamepad, int button) bool IsGamepadButtonDown(int gamepad, int button) bool IsGamepadButtonReleased(int gamepad, int button) bool IsGamepadButtonUp(int gamepad, int button) int GetGamepadButtonPressed(void) int GetGamepadAxisCount(int gamepad) float GetGamepadAxisMovement(int gamepad, int axis) bool IsMouseButtonPressed(int button) bool IsMouseButtonDown(int button) bool IsMouseButtonReleased(int button) bool IsMouseButtonUp(int button) int GetMouseX(void) int GetMouseY(void) Vector2 GetMousePosition(void) void SetMousePosition(int x, int y) void SetMouseOffset(int offsetX, int offsetY) void SetMouseScale(float scaleX, float scaleY) int GetMouseWheelMove(void) int GetTouchX(void) int GetTouchY(void) Vector2 GetTouchPosition(int index) void SetGesturesEnabled(unsigned int gestureFlags) bool IsGestureDetected(int gesture) int GetGestureDetected(void) int GetTouchPointsCount(void) float GetGestureHoldDuration(void) Vector2 GetGestureDragVector(void) float GetGestureDragAngle(void) Vector2 GetGesturePinchVector(void) float GetGesturePinchAngle(void) void SetCameraMode(Camera3D camera, int mode) void UpdateCamera(Camera3D *camera) void SetCameraPanControl(int panKey) void SetCameraAltControl(int altKey) void SetCameraSmoothZoomControl(int szKey) void SetCameraMoveControls(int frontKey, int backKey, int rightKey, int leftKey, int upKey, int downKey) void DrawPixel(int posX, int posY, Color color) void DrawPixelV(Vector2 position, Color color) void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color) void DrawLineV(Vector2 startPos, Vector2 endPos, Color color) void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color) void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color) void DrawLineStrip(Vector2 *points, int numPoints, Color color) void DrawCircle(int centerX, int centerY, float radius, Color color) void DrawCircleSector(Vector2 center, float radius, int startAngle, int endAngle, int segments, Color color) void DrawCircleSectorLines(Vector2 center, float radius, int startAngle, int endAngle, int segments, Color color) void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2) void DrawCircleV(Vector2 center, float radius, Color color) void DrawCircleLines(int centerX, int centerY, float radius, Color color) void DrawRing(Vector2 center, float innerRadius, float outerRadius, (continues on next page) 57.27. Functions 705
745.
Ring Documentation, Release1.16 (continued from previous page) int startAngle, int endAngle, int segments, Color color) void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, int startAngle, int endAngle, int segments, Color color) void DrawRectangle(int posX, int posY, int width, int height, Color color) void DrawRectangleV(Vector2 position, Vector2 size, Color color) void DrawRectangleRec(Rectangle rec, Color color) void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color) void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2) void DrawRectangleGradientH(int posX, int posY, int width, int height, Color color1, Color color2) void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4) void DrawRectangleLines(int posX, int posY, int width, int height, Color color) void DrawRectangleLinesEx(Rectangle rec, int lineThick, Color color) void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color) void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, int lineThick, Color color) void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color) void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color) void DrawTriangleFan(Vector2 *points, int numPoints, Color color) void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color) void SetShapesTexture(Texture2D texture, Rectangle source) bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2) bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2) bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec) Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2) bool CheckCollisionPointRec(Vector2 point, Rectangle rec) bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius) bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3) Image LoadImage(const char *fileName) Image LoadImageEx(Color *pixels, int width, int height) Image LoadImagePro(void *data, int width, int height, int format) Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize) void ExportImage(Image image, const char *fileName) void ExportImageAsCode(Image image, const char *fileName) Texture2D LoadTexture(const char *fileName) Texture2D LoadTextureFromImage(Image image) TextureCubemap LoadTextureCubemap(Image image, int layoutType) RenderTexture2D LoadRenderTexture(int width, int height) void UnloadImage(Image image) void UnloadTexture(Texture2D texture) void UnloadRenderTexture(RenderTexture2D target) Color *GetImageData(Image image) Vector4 *GetImageDataNormalized(Image image) int GetPixelDataSize(int width, int height, int format) Image GetTextureData(Texture2D texture) Image GetScreenData(void) void UpdateTexture(Texture2D texture, const void *pixels) (continues on next page) 57.27. Functions 706
746.
Ring Documentation, Release1.16 (continued from previous page) Image ImageCopy(Image image) void ImageToPOT(Image *image, Color fillColor) void ImageFormat(Image *image, int newFormat) void ImageAlphaMask(Image *image, Image alphaMask) void ImageAlphaClear(Image *image, Color color, float threshold) void ImageAlphaCrop(Image *image, float threshold) void ImageAlphaPremultiply(Image *image) void ImageCrop(Image *image, Rectangle crop) void ImageResize(Image *image, int newWidth, int newHeight) void ImageResizeNN(Image *image, int newWidth,int newHeight) void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color color) void ImageMipmaps(Image *image) void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) Color *ImageExtractPalette(Image image, int maxPaletteSize, int *extractCount) Image ImageText(const char *text, int fontSize, Color color) Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint) void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) void ImageDrawRectangle(Image *dst, Rectangle rec, Color color) void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color) void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color) void ImageDrawTextEx(Image *dst, Vector2 position, Font font, const char *text, float fontSize, float spacing, Color color) void ImageFlipVertical(Image *image) void ImageFlipHorizontal(Image *image) void ImageRotateCW(Image *image) void ImageRotateCCW(Image *image) void ImageColorTint(Image *image, Color color) void ImageColorInvert(Image *image) void ImageColorGrayscale(Image *image) void ImageColorContrast(Image *image, float contrast) void ImageColorBrightness(Image *image, int brightness) void ImageColorReplace(Image *image, Color color, Color replace) Image GenImageColor(int width, int height, Color color) Image GenImageGradientV(int width, int height, Color top, Color bottom) Image GenImageGradientH(int width, int height, Color left, Color right) Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer) Image GenImageChecked(int width, int height, int checksX, int checksY, Color col1, Color col2) Image GenImageWhiteNoise(int width, int height, float factor) Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float scale) Image GenImageCellular(int width, int height, int tileSize) void GenTextureMipmaps(Texture2D *texture) void SetTextureFilter(Texture2D texture, int filterMode) void SetTextureWrap(Texture2D texture, int wrapMode) void DrawTexture(Texture2D texture, int posX, int posY, Color tint) void DrawTextureV(Texture2D texture, Vector2 position, Color tint) void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint) void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint) void DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Rectangle quad, Color tint) (continues on next page) 57.27. Functions 707
747.
Ring Documentation, Release1.16 (continued from previous page) void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint) void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle destRec, Vector2 origin, float rotation, Color tint) Font GetFontDefault(void) Font LoadFont(const char *fileName) Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCount) Font LoadFontFromImage(Image image, Color key, int firstChar) CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int charsCount, int type) Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int padding, int packMethod) void UnloadFont(Font font) void DrawFPS(int posX, int posY) void DrawText(const char *text, int posX, int posY, int fontSize, Color color) void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint) void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint) void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectText, Color selectBack) int MeasureText(const char *text, int fontSize) Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing) int GetGlyphIndex(Font font, int character) int GetNextCodepoint(const char *text, int *count) bool TextIsEqual(const char *text1, const char *text2) unsigned int TextLength(const char *text) unsigned int TextCountCodepoints(const char *text) const char *TextFormat(const char *text) const char *TextSubtext(const char *text, int position, int length) const char *TextReplace(char *text, const char *replace, const char *by) const char *TextInsert(const char *text, const char *insert, int position) const char *TextJoin(const char **textList, int count, const char *delimiter) const char **TextSplit(const char *text, char delimiter, int *count) void TextAppend(char *text, const char *append, int *position) int TextFindIndex(const char *text, const char *find) const char *TextToUpper(const char *text) const char *TextToLower(const char *text) const char *TextToPascal(const char *text) int TextToInteger(const char *text) void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color) void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color) void DrawCube(Vector3 position, float width, float height, float length, Color color) void DrawCubeV(Vector3 position, Vector3 size, Color color) void DrawCubeWires(Vector3 position, float width, float height, float length, Color color) void DrawCubeWiresV(Vector3 position, Vector3 size, Color color) void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float height, float length, Color color) void DrawSphere(Vector3 centerPos, float radius, Color color) void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color) void DrawSphereWires(Vector3 centerPos, float radius, int rings, (continues on next page) 57.27. Functions 708
748.
Ring Documentation, Release1.16 (continued from previous page) int slices, Color color) void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color) void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color) void DrawPlane(Vector3 centerPos, Vector2 size, Color color) void DrawRay(Ray ray, Color color) void DrawGrid(int slices, float spacing) void DrawGizmo(Vector3 position) Model LoadModel(const char *fileName) Model LoadModelFromMesh(Mesh mesh) void UnloadModel(Model model) Mesh *LoadMeshes(const char *fileName, int *meshCount) void ExportMesh(Mesh mesh, const char *fileName) void UnloadMesh(Mesh *mesh) Material *LoadMaterials(const char *fileName, int *materialCount) Material LoadMaterialDefault(void) void UnloadMaterial(Material material) void SetMaterialTexture(Material *material, int mapType, Texture2D texture) void SetModelMeshMaterial(Model *model, int meshId, int materialId) ModelAnimation *LoadModelAnimations(const char *fileName, int *animsCount) void UpdateModelAnimation(Model model, ModelAnimation anim, int frame) void UnloadModelAnimation(ModelAnimation anim) bool IsModelAnimationValid(Model model, ModelAnimation anim) Mesh GenMeshPoly(int sides, float radius) Mesh GenMeshPlane(float width, float length, int resX, int resZ) Mesh GenMeshCube(float width, float height, float length) Mesh GenMeshSphere(float radius, int rings, int slices) Mesh GenMeshHemiSphere(float radius, int rings, int slices) Mesh GenMeshCylinder(float radius, float height, int slices) Mesh GenMeshTorus(float radius, float size, int radSeg, int sides) Mesh GenMeshKnot(float radius, float size, int radSeg, int sides) Mesh GenMeshHeightmap(Image heightmap, Vector3 size) Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize) BoundingBox MeshBoundingBox(Mesh mesh) void MeshTangents(Mesh *mesh) void MeshBinormals(Mesh *mesh) void DrawModel(Model model, Vector3 position, float scale, Color tint) void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint) void DrawModelWires(Model model, Vector3 position, float scale, Color tint) void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint) void DrawBoundingBox(BoundingBox box, Color color) void DrawBillboard(Camera3D camera, Texture2D texture, Vector3 center, float size, Color tint) void DrawBillboardRec(Camera3D camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint) bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB) bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2) bool CheckCollisionBoxSphere(BoundingBox box, Vector3 centerSphere, float ˓ →radiusSphere) bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius) bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadius, Vector3 *collisionPoint) bool CheckCollisionRayBox(Ray ray, BoundingBox box) (continues on next page) 57.27. Functions 709
749.
Ring Documentation, Release1.16 (continued from previous page) RayHitInfo GetCollisionRayModel(Ray ray, Model *model) RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3) RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight) char *LoadText(const char *fileName) Shader LoadShader(const char *vsFileName, const char *fsFileName) Shader LoadShaderCode(char *vsCode, char *fsCode) void UnloadShader(Shader shader) Shader GetShaderDefault(void) Texture2D GetTextureDefault(void) int GetShaderLocation(Shader shader, const char *uniformName) void SetShaderValue(Shader shader, int uniformLoc, const void *value, int uniformType) void SetShaderValueV(Shader shader, int uniformLoc, const void *value, int uniformType, int count) void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat) void SetShaderValueTexture(Shader shader, int uniformLoc, Texture2D texture) void SetMatrixProjection(Matrix proj) void SetMatrixModelview(Matrix view) Matrix GetMatrixModelview(void) Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size) Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size) Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size) Texture2D GenTextureBRDF(Shader shader, int size) void BeginShaderMode(Shader shader) void EndShaderMode(void) void BeginBlendMode(int mode) void EndBlendMode(void) void BeginScissorMode(int x, int y, int width, int height) void EndScissorMode(void) void InitVrSimulator(void) void CloseVrSimulator(void) void UpdateVrTracking(Camera3D *camera) void SetVrConfiguration(VrDeviceInfo info, Shader distortion) bool IsVrSimulatorReady(void) void ToggleVrMode(void) void BeginVrDrawing(void) void EndVrDrawing(void) void InitAudioDevice(void) void CloseAudioDevice(void) bool IsAudioDeviceReady(void) void SetMasterVolume(float volume) Wave LoadWave(const char *fileName) Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels) Sound LoadSound(const char *fileName) Sound LoadSoundFromWave(Wave wave) void UpdateSound(Sound sound, const void *data, int samplesCount) void UnloadWave(Wave wave) void UnloadSound(Sound sound) void ExportWave(Wave wave, const char *fileName) void ExportWaveAsCode(Wave wave, const char *fileName) void PlaySound(Sound sound) void PauseSound(Sound sound) void ResumeSound(Sound sound) void StopSound(Sound sound) bool IsSoundPlaying(Sound sound) void SetSoundVolume(Sound sound, float volume) (continues on next page) 57.27. Functions 710
Ring Documentation, Release1.16 (continued from previous page) int maxValue, bool editMode) bool GuiValueBox(Rectangle bounds, int *value, int minValue, int maxValue, bool editMode) bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode) float GuiSlider(Rectangle bounds, const char *text, float value, float minValue, float maxValue, bool showValue) float GuiSliderBar(Rectangle bounds, const char *text, float value, float minValue, float maxValue, bool showValue) float GuiProgressBar(Rectangle bounds, const char *text, float value, float minValue, float maxValue, bool showValue) void GuiStatusBar(Rectangle bounds, const char *text) void GuiDummyRec(Rectangle bounds, const char *text) int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) Vector2 GuiGrid(Rectangle bounds, float spacing, int subdivs) bool GuiListView(Rectangle bounds, const char *text, int *active, int *scrollIndex, bool editMode) bool GuiListViewEx(Rectangle bounds, const char **text, int count, int *enabled, int *active, int *focus, int *scrollIndex, bool editMode) int GuiMessageBox(Rectangle bounds, const char *windowTitle, const char *message, const char *buttons) int GuiTextInputBox(Rectangle bounds, const char *windowTitle, const char *message, char *text, const char *buttons) Color GuiColorPicker(Rectangle bounds, Color color) void GuiLoadStyle(const char *fileName) void GuiLoadStyleProps(const int *props, int count) void GuiLoadStyleDefault(void) void GuiUpdateStyleComplete(void) const char *GuiIconText(int iconId, const char *text) 57.27. Functions 712
752.
CHAPTER FIFTYEIGHT USING RINGOPENGL ANDRINGFREEGLUT FOR 3D GRAPHICS In this chapter we will learn about using RingOpenGL 58.1 Samples Source (Authors) The samples in this chapter are based on C Tutorials from (1) http://www.lighthouse3d.com/tutorials/glut-tutorial/ (2) http://www.wikihow.com/Make-a-Cube-in-OpenGL 58.2 What is RingOpenGL? RingOpenGL contains the Ring binding to the OpenGL library You can learn about OpenGL from : https://www.opengl.org/ RingOpenGL comes with support for the next versions • OpenGL 1.1 • OpenGL 1.2 • OpenGL 1.3 • OpenGL 1.4 • OpenGL 1.5 • OpenGL 2.0 • OpenGL 2.1 • OpenGL 3.0 • OpenGL 3.2 • OpenGL 3.3 • OpenGL 4.0 • OpenGL 4.1 • OpenGL 4.2 • OpenGL 4.3 713
753.
Ring Documentation, Release1.16 • OpenGL 4.4 • OpenGL 4.5 • OpenGL 4.6 For example, if you want to use OpenGL 2.1 then load RingOpenGL 2.1 library load "opengl21lib.ring" 58.3 What is RingFreeGLUT? RingFreeGLUT contains the Ring binding to the FreeGLUT library You can learn about FreeGLUT from : http://freeglut.sourceforge.net/ To use the RingFreeGLUT library, Just load the library load "freeglut.ring" 58.4 The First Window using RingFreeGLUT Example: load "freeglut.ring" func main glutInit() glutInitDisplayMode(GLUT_SINGLE) glutInitWindowSize(800, 600) glutInitWindowPosition(100, 10) glutCreateWindow("RingFreeGLUT - Test 1") glutDisplayFunc(:displayCode) glutMainLoop() func displaycode Screen Shot 58.3. What is RingFreeGLUT? 714
754.
Ring Documentation, Release1.16 58.5 Drawing using RingOpenGL Example: load "freeglut.ring" load "opengl21lib.ring" func main glutInit() glutInitDisplayMode(GLUT_SINGLE) glutInitWindowSize(800, 600) glutInitWindowPosition(100, 10) glutCreateWindow("RingFreeGLUT - Test 2") glutDisplayFunc(:displayCode) glutMainLoop() func displaycode glClear(GL_COLOR_BUFFER_BIT) glColor3f(0,255,0) glBegin(GL_POLYGON) (continues on next page) 58.5. Drawing using RingOpenGL 715
Ring Documentation, Release1.16 58.6 The First Triangle Example: load "freeglut.ring" load "opengl21lib.ring" func main glutInit() glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA) glutInitWindowSize(320,320) glutInitWindowPosition(100, 10) glutCreateWindow("RingFreeGLUT - Test 3") glutDisplayFunc(:renderScene) glutMainLoop() func renderScene glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glBegin(GL_TRIANGLES) glVertex3f(-0.5,-0.5,0.0) glVertex3f(0.5,0.0,0.0) glVertex3f(0.0,0.5,0.0) glEnd() glutSwapBuffers() Screen Shot 58.6. The First Triangle 717
757.
Ring Documentation, Release1.16 58.7 Window Resize Event Example: load "freeglut.ring" load "opengl21lib.ring" func main // init GLUT and create window glutInit() glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA) glutInitWindowPosition(100,100) glutInitWindowSize(320,320) glutCreateWindow("RingFreeGLUT - Test 4") glutDisplayFunc(:renderScene) glutReshapeFunc(:changeSize) glutMainLoop() func renderScene glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glBegin(GL_TRIANGLES) glVertex3f(-2,-2,-5.0) glVertex3f(2,0.0,-5.0) glVertex3f(0.0,2,-5.0) glEnd() glutSwapBuffers() func changesize h = glutEventHeight() w = glutEventWidth() // Prevent a divide by zero, when window is too short // (you cant make a window of zero width). if (h = 0) h = 1 ok ratio = w * 1.0 / h // Use the Projection Matrix glMatrixMode(GL_PROJECTION) // Reset Matrix glLoadIdentity() // Set the viewport to be the entire window glViewport(0, 0, w, h) // Set the correct perspective. gluPerspective(45,ratio,1,100) (continues on next page) 58.7. Window Resize Event 718
758.
Ring Documentation, Release1.16 (continued from previous page) // Get Back to the Modelview glMatrixMode(GL_MODELVIEW) 58.8 Triangle Rotation Example: load "freeglut.ring" load "opengl21lib.ring" angle = 0 func main // init GLUT and create window glutInit() glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA) glutInitWindowPosition(100,100) glutInitWindowSize(320,320) glutCreateWindow("RingFreeGLUT - Test 5") glutDisplayFunc(:renderScene) glutReshapeFunc(:changeSize) glutIdleFunc(:renderScene) glutMainLoop() func renderScene // Clear Color and Depth Buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) // Reset transformations glLoadIdentity() // Set the camera gluLookAt( 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) glRotatef(angle, 0.0, 1.0, 0.0) glBegin(GL_TRIANGLES) glVertex3f(-2.0,-2.0, 0.0) glVertex3f( 2.0, 0.0, 0.0) glVertex3f( 0.0, 2.0, 0.0) glEnd() angle+=0.1 glutSwapBuffers(); func changesize (continues on next page) 58.8. Triangle Rotation 719
759.
Ring Documentation, Release1.16 (continued from previous page) h = glutEventHeight() w = glutEventWidth() // Prevent a divide by zero, when window is too short // (you cant make a window of zero width). if (h = 0) h = 1 ok ratio = w * 1.0 / h // Use the Projection Matrix glMatrixMode(GL_PROJECTION) // Reset Matrix glLoadIdentity() // Set the viewport to be the entire window glViewport(0, 0, w, h) // Set the correct perspective. gluPerspective(45,ratio,1,100) // Get Back to the Modelview glMatrixMode(GL_MODELVIEW) Screen Shot 58.8. Triangle Rotation 720
760.
Ring Documentation, Release1.16 58.9 Keyboard Events and Colors Example: load "freeglut.ring" load "opengl21lib.ring" angle = 0 red=1.0 blue=1.0 green=1.0 func main // init GLUT and create window glutInit() glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA) glutInitWindowPosition(100,100) glutInitWindowSize(320,320) glutCreateWindow("RingFreeGLUT - Test 6") glutDisplayFunc(:renderScene) glutReshapeFunc(:changeSize) glutIdleFunc(:renderScene) // here are the new entries glutKeyboardFunc(:processNormalKeys) glutSpecialFunc(:processSpecialKeys) glutMainLoop() func renderScene // Clear Color and Depth Buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) // Reset transformations glLoadIdentity() // Set the camera gluLookAt( 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) glRotatef(angle, 0.0, 1.0, 0.0) glColor3f(red,green,blue); glBegin(GL_TRIANGLES) glVertex3f(-2.0,-2.0, 0.0) glVertex3f( 2.0, 0.0, 0.0) glVertex3f( 0.0, 2.0, 0.0) glEnd() angle+=0.1 (continues on next page) 58.9. Keyboard Events and Colors 721
761.
Ring Documentation, Release1.16 (continued from previous page) glutSwapBuffers(); func changesize h = glutEventHeight() w = glutEventWidth() // Prevent a divide by zero, when window is too short // (you cant make a window of zero width). if (h = 0) h = 1 ok ratio = w * 1.0 / h // Use the Projection Matrix glMatrixMode(GL_PROJECTION) // Reset Matrix glLoadIdentity() // Set the viewport to be the entire window glViewport(0, 0, w, h) // Set the correct perspective. gluPerspective(45,ratio,1,100) // Get Back to the Modelview glMatrixMode(GL_MODELVIEW) func processNormalKeys key = GLUTEventKey() if key = 27 shutdown() ok func processSpecialKeys key = GLUTEventKey() switch key on GLUT_KEY_F1 red = 1.0 green = 0.0 blue = 0.0 on GLUT_KEY_F2 red = 0.0 green = 1.0 blue = 0.0 on GLUT_KEY_F3 red = 0.0 green = 0.0 blue = 1.0 off Screen Shot 58.9. Keyboard Events and Colors 722
762.
Ring Documentation, Release1.16 58.10 The Camera Example: load "freeglut.ring" load "opengl21lib.ring" // angle of rotation for the camera direction angle=0.0 // actual vector representing the camera's direction lx=0.0 lz=-1.0 // XZ position of the camera x=0.0 z=5.0 func drawSnowMan glColor3f(1.0, 1.0, 1.0) // Draw Body glTranslatef(0.0 ,0.75, 0.0) glutSolidSphere(0.75,20,20) // Draw Head glTranslatef(0.0, 1.0, 0.0) glutSolidSphere(0.25,20,20) // Draw Eyes glPushMatrix() glColor3f(0.0,0.0,0.0) (continues on next page) 58.10. The Camera 723
763.
Ring Documentation, Release1.16 (continued from previous page) glTranslatef(0.05, 0.10, 0.18) glutSolidSphere(0.05,10,10) glTranslatef(-0.1, 0.0, 0.0) glutSolidSphere(0.05,10,10) glPopMatrix() // Draw Nose glColor3f(1.0, 0.5 , 0.5) glutSolidCone(0.08,0.5,10,2) func changeSize w = glutEventWidth() h = glutEventHeight() // Prevent a divide by zero, when window is too short // (you cant make a window of zero width). if h = 0 h = 1 ok ratio = w * 1.0 / h // Use the Projection Matrix glMatrixMode(GL_PROJECTION) // Reset Matrix glLoadIdentity() // Set the viewport to be the entire window glViewport(0, 0, w, h) // Set the correct perspective. gluPerspective(45.0, ratio, 0.1, 100.0); // Get Back to the Modelview glMatrixMode(GL_MODELVIEW) func processNormalKeys key = glutEventKey() if key = 27 shutdown() ok func renderScene // Clear Color and Depth Buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) // Reset transformations (continues on next page) 58.10. The Camera 724
764.
Ring Documentation, Release1.16 (continued from previous page) glLoadIdentity() // Set the camera gluLookAt( x, 1.0, z, x+lx, 1.0, z+lz, 0.0, 1.0, 0.0) // Draw ground glColor3f(0.9, 0.9, 0.9) glBegin(GL_QUADS) glVertex3f(-100.0, 0.0, -100.0) glVertex3f(-100.0, 0.0, 100.0) glVertex3f( 100.0, 0.0, 100.0) glVertex3f( 100.0, 0.0, -100.0) glEnd() // Draw 36 SnowMen for i = -3 to 2 for j=-3 to 2 glPushMatrix() glTranslatef(i*10.0,0,j * 10.0) drawSnowMan() glPopMatrix() next next glutSwapBuffers() func processSpecialKeys key = glutEventKey() fraction = 0.1 switch key on GLUT_KEY_LEFT angle -= 0.01 lx = sin(angle) lz = -cos(angle) on GLUT_KEY_RIGHT angle += 0.01 lx = sin(angle) lz = -cos(angle) on GLUT_KEY_UP x += lx * fraction z += lz * fraction on GLUT_KEY_DOWN x -= lx * fraction z -= lz * fraction off func main // init GLUT and create window (continues on next page) 58.10. The Camera 725
765.
Ring Documentation, Release1.16 (continued from previous page) glutInit() glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA) glutInitWindowPosition(100,100) glutInitWindowSize(320,320) glutCreateWindow("RingFreeGLUT - Test 7") // register callbacks glutDisplayFunc(:renderScene) glutReshapeFunc(:changeSize) glutIdleFunc(:renderScene) glutKeyboardFunc(:processNormalKeys) glutSpecialFunc(:processSpecialKeys) // OpenGL init glEnable(GL_DEPTH_TEST) // enter GLUT event processing cycle glutMainLoop() Screen Shot Another Example: load "freeglut.ring" load "opengl21lib.ring" // angle of rotation for the camera direction angle = 0.0 // actual vector representing the camera's direction lx=0.0 lz=-1.0 (continues on next page) 58.10. The Camera 726
766.
Ring Documentation, Release1.16 (continued from previous page) // XZ position of the camera x=0.0 z=5.0 // the key states. These variables will be zero //when no key is being presses deltaAngle = 0.0 deltaMove = 0 func changeSize w = glutEventWidth() h = glutEventHeight() // Prevent a divide by zero, when window is too short // (you cant make a window of zero width). if h = 0 h = 1 ok ratio = w * 1.0 / h // Use the Projection Matrix glMatrixMode(GL_PROJECTION) // Reset Matrix glLoadIdentity() // Set the viewport to be the entire window glViewport(0, 0, w, h) // Set the correct perspective. gluPerspective(45.0, ratio, 0.1, 100.0) // Get Back to the Modelview glMatrixMode(GL_MODELVIEW) func drawSnowMan glColor3f(1.0, 1.0, 1.0) // Draw Body glTranslatef(0.0 ,0.75, 0.0) glutSolidSphere(0.75,20,20) // Draw Head glTranslatef(0.0, 1.0, 0.0) glutSolidSphere(0.25,20,20) // Draw Eyes glPushMatrix() glColor3f(0.0,0.0,0.0) glTranslatef(0.05, 0.10, 0.18) glutSolidSphere(0.05,10,10) glTranslatef(-0.1, 0.0, 0.0) glutSolidSphere(0.05,10,10) glPopMatrix() (continues on next page) 58.10. The Camera 727
767.
Ring Documentation, Release1.16 (continued from previous page) // Draw Nose glColor3f(1.0, 0.5 , 0.5) glRotatef(0.0,1.0, 0.0, 0.0) glutSolidCone(0.08,0.5,10,2) func computePos deltaMove x += deltaMove * lx * 0.1 z += deltaMove * lz * 0.1 func computeDir deltaAngle angle += deltaAngle lx = sin(angle) lz = -cos(angle) func renderScene if deltaMove computePos(deltaMove) ok if deltaAngle computeDir(deltaAngle) ok // Clear Color and Depth Buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) // Reset transformations glLoadIdentity() // Set the camera gluLookAt( x, 1.0, z, x+lx, 1.0, z+lz, 0.0, 1.0, 0.0) // Draw ground glColor3f(0.9, 0.9, 0.9) glBegin(GL_QUADS) glVertex3f(-100.0, 0.0, -100.0) glVertex3f(-100.0, 0.0, 100.0) glVertex3f( 100.0, 0.0, 100.0) glVertex3f( 100.0, 0.0, -100.0) glEnd() // Draw 36 SnowMen for i = -3 to 2 for j=-3 to 2 glPushMatrix() glTranslatef(i*10.0,0,j * 10.0) drawSnowMan() glPopMatrix() (continues on next page) 58.10. The Camera 728
768.
Ring Documentation, Release1.16 (continued from previous page) next next glutSwapBuffers() func pressKey key = glutEventKey() xx = glutEventX() yy = glutEventY() switch key on GLUT_KEY_LEFT deltaAngle = -0.01 on GLUT_KEY_RIGHT deltaAngle = 0.01 on GLUT_KEY_UP deltaMove = 0.5 on GLUT_KEY_DOWN deltaMove = -0.5 off func releaseKey key = glutEventKey() switch key on GLUT_KEY_LEFT deltaAngle = 0.0 on GLUT_KEY_RIGHT deltaAngle = 0.0 on GLUT_KEY_UP deltaMove = 0 on GLUT_KEY_DOWN deltaMove = 0 off func main // init GLUT and create window glutInit() glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA) glutInitWindowPosition(100,100) glutInitWindowSize(320,320) glutCreateWindow("RingFreeGLUT - Test 8") // register callbacks glutDisplayFunc(:renderScene) glutReshapeFunc(:changeSize) glutIdleFunc(:renderScene) glutSpecialFunc(:pressKey) // here are the new entries glutIgnoreKeyRepeat(1) glutSpecialUpFunc(:releaseKey) // OpenGL init (continues on next page) 58.10. The Camera 729
769.
Ring Documentation, Release1.16 (continued from previous page) glEnable(GL_DEPTH_TEST) // enter GLUT event processing cycle glutMainLoop() 58.11 Mouse Events Example: load "freeglut.ring" load "opengl21lib.ring" // angle of rotation for the camera direction angle = 0.0 // actual vector representing the camera's direction lx=0.0 lz=-1.0 // XZ position of the camera x=0.0 z=5.0 // the key states. These variables will be zero //when no key is being presses deltaAngle = 0.0 deltaMove = 0.0 xOrigin = -1 func changeSize w = glutEventWidth() h = glutEventHeight() // Prevent a divide by zero, when window is too short // (you cant make a window of zero width). if h = 0 h = 1 ok ratio = w * 1.0 / h // Use the Projection Matrix glMatrixMode(GL_PROJECTION) // Reset Matrix glLoadIdentity() // Set the viewport to be the entire window glViewport(0, 0, w, h) // Set the correct perspective. gluPerspective(45.0, ratio, 0.1, 100.0) // Get Back to the Modelview glMatrixMode(GL_MODELVIEW) (continues on next page) 58.11. Mouse Events 730
770.
Ring Documentation, Release1.16 (continued from previous page) func drawSnowMan glColor3f(1.0, 1.0, 1.0) // Draw Body glTranslatef(0.0 ,0.75, 0.0) glutSolidSphere(0.75,20,20) // Draw Head glTranslatef(0.0, 1.0, 0.0) glutSolidSphere(0.25,20,20) // Draw Eyes glPushMatrix() glColor3f(0.0,0.0,0.0) glTranslatef(0.05, 0.10, 0.18) glutSolidSphere(0.05,10,10) glTranslatef(-0.1, 0.0, 0.0) glutSolidSphere(0.05,10,10) glPopMatrix() // Draw Nose glColor3f(1.0, 0.5 , 0.5) glRotatef(0.0,1.0, 0.0, 0.0) glutSolidCone(0.08,0.5,10,2) func computePos deltaMove x += deltaMove * lx * 0.1 z += deltaMove * lz * 0.1 func renderScene if deltaMove computePos(deltaMove) ok // Clear Color and Depth Buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) // Reset transformations glLoadIdentity() // Set the camera gluLookAt( x, 1.0, z, x+lx, 1.0, z+lz, 0.0, 1.0, 0.0) // Draw ground glColor3f(0.9, 0.9, 0.9) glBegin(GL_QUADS) glVertex3f(-100.0, 0.0, -100.0) glVertex3f(-100.0, 0.0, 100.0) glVertex3f( 100.0, 0.0, 100.0) glVertex3f( 100.0, 0.0, -100.0) (continues on next page) 58.11. Mouse Events 731
771.
Ring Documentation, Release1.16 (continued from previous page) glEnd() // Draw 36 SnowMen for i = -3 to 2 for j=-3 to 2 glPushMatrix() glTranslatef(i*10.0,0,j * 10.0) drawSnowMan() glPopMatrix() next next glutSwapBuffers() func processNormalKeys key = glutEventKey() if key = 27 shutdown() ok func pressKey key = glutEventKey() switch key on GLUT_KEY_UP deltaMove = 0.5 on GLUT_KEY_DOWN deltaMove = -0.5 off func releaseKey key = glutEventKey() switch key on GLUT_KEY_UP deltaMove = 0 on GLUT_KEY_DOWN deltaMove = 0 off func mouseMove xx = glutEventX() yy = glutEventY() // this will only be true when the left button is down if xOrigin >= 0 // update deltaAngle deltaAngle = (xx - xOrigin) * 0.001 // update camera's direction lx = sin(angle + deltaAngle) lz = -cos(angle + deltaAngle) ok (continues on next page) 58.11. Mouse Events 732
772.
Ring Documentation, Release1.16 (continued from previous page) func mouseButton button = glutEventButton() state = glutEventState() xx = glutEventX() yy = glutEventY() // only start motion if the left button is pressed if button = GLUT_LEFT_BUTTON // when the button is released if state = GLUT_UP angle += deltaAngle xOrigin = -1 else // state = GLUT_DOWN xOrigin = xx ok fflush(stdout) ok func main // init GLUT and create window glutInit() glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA) glutInitWindowPosition(100,100) glutInitWindowSize(320,320) glutCreateWindow("RingFreeGLUT - Test 9") // register callbacks glutDisplayFunc(:renderScene) glutReshapeFunc(:changeSize) glutIdleFunc(:renderScene) glutIgnoreKeyRepeat(1) glutKeyboardFunc(:processNormalKeys) glutSpecialFunc(:pressKey) glutSpecialUpFunc(:releaseKey) // here are the two new functions glutMouseFunc(:mouseButton) glutMotionFunc(:mouseMove) // OpenGL init glEnable(GL_DEPTH_TEST) // enter GLUT event processing cycle glutMainLoop() 58.11. Mouse Events 733
773.
Ring Documentation, Release1.16 58.12 Menu Events Example: load "freeglut.ring" load "opengl21lib.ring" // angle of rotation for the camera direction angle = 0.0 // actual vector representing the camera's direction lx=0.0 lz=-1.0 // XZ position of the camera x=0.0 z=5.0 // the key states. These variables will be zero //when no key is being presses deltaAngle = 0.0 deltaMove = 0 xOrigin = -1 // Constant definitions for Menus // for RingFreeGLUT - We must have different ID for each menu item C_RED = 1 C_GREEN = 2 C_BLUE = 3 C_ORANGE = 4 C_FILL = 5 C_LINE = 6 C_SHRINK = 7 C_NORMAL = 8 // Pop up menu identifiers fillMenu= 0 shrinkMenu= 0 mainMenu=0 colorMenu=0 // color for the nose red = 1.0 blue=0.5 green=0.5 // scale of snowman scale = 1.0 // menu status menuFlag = 0 func changeSize w = glutEventWidth() h = glutEventHeight() // Prevent a divide by zero, when window is too short (continues on next page) 58.12. Menu Events 734
774.
Ring Documentation, Release1.16 (continued from previous page) // (you cant make a window of zero width). if h = 0 h = 1 ok ratio = w * 1.0 / h // Use the Projection Matrix glMatrixMode(GL_PROJECTION) // Reset Matrix glLoadIdentity() // Set the viewport to be the entire window glViewport(0, 0, w, h) // Set the correct perspective. gluPerspective(45.0, ratio, 0.1, 100.0) // Get Back to the Modelview glMatrixMode(GL_MODELVIEW) func drawSnowMan glScalef(scale, scale, scale) glColor3f(1.0, 1.0, 1.0) // Draw Body glTranslatef(0.0 ,0.75, 0.0) glutSolidSphere(0.75,20,20) // Draw Head glTranslatef(0.0, 1.0, 0.0) glutSolidSphere(0.25,20,20) // Draw Eyes glPushMatrix() glColor3f(0.0,0.0,0.0) glTranslatef(0.05, 0.10, 0.18) glutSolidSphere(0.05,10,10) glTranslatef(-0.1, 0.0, 0.0) glutSolidSphere(0.05,10,10) glPopMatrix() // Draw Nose glColor3f(red, green, blue) glRotatef(0.0,1.0, 0.0, 0.0) glutSolidCone(0.08,0.5,10,2) glColor3f(1.0, 1.0, 1.0) func computePos deltaMove x += deltaMove * lx * 0.1 z += deltaMove * lz * 0.1 (continues on next page) 58.12. Menu Events 735
775.
Ring Documentation, Release1.16 (continued from previous page) func renderScene if deltaMove computePos(deltaMove) ok // Clear Color and Depth Buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) // Reset transformations glLoadIdentity() // Set the camera gluLookAt( x, 1.0, z, x+lx, 1.0, z+lz, 0.0, 1.0, 0.0) // Draw ground glColor3f(0.9, 0.9, 0.9) glBegin(GL_QUADS) glVertex3f(-100.0, 0.0, -100.0) glVertex3f(-100.0, 0.0, 100.0) glVertex3f( 100.0, 0.0, 100.0) glVertex3f( 100.0, 0.0, -100.0) glEnd() // Draw 36 SnowMen for i = -3 to 2 for j = -3 to 2 glPushMatrix() glTranslatef(i*10.0, 0.0, j * 10.0) drawSnowMan() glPopMatrix() next next glutSwapBuffers() // ----------------------------------- // KEYBOARD // ----------------------------------- func processNormalKeys key = glutEventKey() xx = glutEventX() yy = glutEventY() glutSetMenu(mainMenu) switch key on 27 glutDestroyMenu(mainMenu) glutDestroyMenu(fillMenu) glutDestroyMenu(colorMenu) glutDestroyMenu(shrinkMenu) shutdown() (continues on next page) 58.12. Menu Events 736
776.
Ring Documentation, Release1.16 (continued from previous page) on 's' if not menuFlag glutChangeToSubMenu(2,"Shrink",shrinkMenu) ok on 'c' if not menuFlag glutChangeToSubMenu(2,"Color",colorMenu) ok off if key = 27 shutdown() ok func pressKey key = glutEventKey() xx = glutEventX() yy = glutEventY() switch key on GLUT_KEY_UP deltaMove = 0.5 on GLUT_KEY_DOWN deltaMove = -0.5 off func releaseKey key = glutEventKey() switch key on GLUT_KEY_UP deltaMove = 0 on GLUT_KEY_DOWN deltaMove = 0 off // ----------------------------------- // MOUSE // ----------------------------------- func mouseMove xx = glutEventX() yy = glutEventY() // this will only be true when the left button is down if xOrigin >= 0 // update deltaAngle deltaAngle = (xx - xOrigin) * 0.001 // update camera's direction lx = sin(angle + deltaAngle) (continues on next page) 58.12. Menu Events 737
777.
Ring Documentation, Release1.16 (continued from previous page) lz = -cos(angle + deltaAngle) ok func mouseButton button = glutEventButton() state = glutEventState() xx = glutEventX() yy = glutEventY() // only start motion if the left button is pressed if button = GLUT_LEFT_BUTTON // when the button is released if state = GLUT_UP angle += deltaAngle xOrigin = -1 else // state = GLUT_DOWN xOrigin = xx ok ok // ----------------------------------- // MENUS // ----------------------------------- func processMenuStatus status = glutEventStatus() xx = glutEventX() yy = glutEventY() if status = GLUT_MENU_IN_USE menuFlag = 1 else menuFlag = 0 ok func processMainMenu // nothing to do in here // all actions are for submenus func processFillMenu option = glutEventValue() switch option on C_FILL glPolygonMode(GL_FRONT, GL_FILL) on C_LINE glPolygonMode(GL_FRONT, GL_LINE) (continues on next page) 58.12. Menu Events 738
778.
Ring Documentation, Release1.16 (continued from previous page) off func processShrinkMenu option = glutEventValue() switch option on C_SHRINK scale = 0.5 on C_NORMAL scale = 1.0 off func processColorMenu option = glutEventValue() switch option on C_RED red = 1.0 green = 0.0 blue = 0.0 on C_GREEN red = 0.0 green = 1.0 blue = 0.0 on C_BLUE red = 0.0 green = 0.0 blue = 1.0 on C_ORANGE red = 1.0 green = 0.5 blue = 0.5 off func createPopupMenus shrinkMenu = glutCreateMenu(:processShrinkMenu) glutAddMenuEntry("Shrink",C_SHRINK) glutAddMenuEntry("NORMAL",C_NORMAL) fillMenu = glutCreateMenu(:processFillMenu) glutAddMenuEntry("Fill",C_FILL) glutAddMenuEntry("Line",C_LINE) colorMenu = glutCreateMenu(:processColorMenu) glutAddMenuEntry("Red",C_RED) glutAddMenuEntry("Blue",C_BLUE) glutAddMenuEntry("Green",C_GREEN) glutAddMenuEntry("Orange",C_ORANGE) (continues on next page) 58.12. Menu Events 739
779.
Ring Documentation, Release1.16 (continued from previous page) mainMenu = glutCreateMenu(:processMainMenu) glutAddSubMenu("Polygon Mode", fillMenu) glutAddSubMenu("Color", colorMenu) // attach the menu to the right button glutAttachMenu(GLUT_RIGHT_BUTTON) // this will allow us to know if the menu is active glutMenuStatusFunc(:processMenuStatus) // ----------------------------------- // MAIN // ----------------------------------- func main // init GLUT and create window glutInit() glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA) glutInitWindowPosition(100,100) glutInitWindowSize(320,320) glutCreateWindow("RingFreeGLUT - Test 10") // register callbacks glutDisplayFunc(:renderScene) glutReshapeFunc(:changeSize) glutIdleFunc(:renderScene) glutIgnoreKeyRepeat(1) glutKeyboardFunc(:processNormalKeys) glutSpecialFunc(:pressKey) glutSpecialUpFunc(:releaseKey) // here are the two new functions glutMouseFunc(:mouseButton) glutMotionFunc(:mouseMove) // OpenGL init glEnable(GL_DEPTH_TEST) glEnable(GL_CULL_FACE) // init Menus createPopupMenus() // enter GLUT event processing cycle glutMainLoop() Screen Shot 58.12. Menu Events 740
780.
Ring Documentation, Release1.16 58.13 Using Fonts Example: load "freeglut.ring" load "opengl21lib.ring" // angle of rotation for the camera direction angle = 0.0 // actual vector representing the camera's direction lx=0.0 lz=-1.0 // XZ position of the camera x=0.0 z=5.0 // the key states. These variables will be zero //when no key is being presses deltaAngle = 0.0 deltaMove = 0 xOrigin = -1 // Constant definitions for Menus C_RED = 1 C_GREEN = 2 C_BLUE = 3 C_ORANGE = 4 C_FILL = 5 C_LINE = 6 (continues on next page) 58.13. Using Fonts 741
781.
Ring Documentation, Release1.16 (continued from previous page) // Pop up menu identifiers fillMenu=NULL fontMenu=NULL mainMenu=NULL colorMenu=NULL // color for the nose red = 1.0 blue=0.5 green=0.5 // scale of snowman scale = 1.0 // menu status menuFlag = 0 // default font font = GLUT_BITMAP_TIMES_ROMAN_24 C_INT_GLUT_BITMAP_8_BY_13 = 7 C_INT_GLUT_BITMAP_9_BY_15 = 8 C_INT_GLUT_BITMAP_TIMES_ROMAN_10 = 9 C_INT_GLUT_BITMAP_TIMES_ROMAN_24 = 10 C_INT_GLUT_BITMAP_HELVETICA_10 = 11 C_INT_GLUT_BITMAP_HELVETICA_12 = 12 C_INT_GLUT_BITMAP_HELVETICA_18 = 13 func changeSize w = glutEventWidth() h = glutEventHeight() // Prevent a divide by zero, when window is too short // (you cant make a window of zero width). if h = 0 h = 1 ok ratio = w * 1.0 / h // Use the Projection Matrix glMatrixMode(GL_PROJECTION) // Reset Matrix glLoadIdentity() // Set the viewport to be the entire window glViewport(0, 0, w, h) // Set the correct perspective. gluPerspective(45.0, ratio, 0.1, 100.0) // Get Back to the Modelview glMatrixMode(GL_MODELVIEW) func drawSnowMan (continues on next page) 58.13. Using Fonts 742
782.
Ring Documentation, Release1.16 (continued from previous page) glScalef(scale, scale, scale) glColor3f(1.0, 1.0, 1.0) // Draw Body glTranslatef(0.0 ,0.75, 0.0) glutSolidSphere(0.75,20,20) // Draw Head glTranslatef(0.0, 1.0, 0.0) glutSolidSphere(0.25,20,20) // Draw Eyes glPushMatrix() glColor3f(0.0,0.0,0.0) glTranslatef(0.05, 0.10, 0.18) glutSolidSphere(0.05,10,10) glTranslatef(-0.1, 0.0, 0.0) glutSolidSphere(0.05,10,10) glPopMatrix() // Draw Nose glColor3f(red, green, blue) glRotatef(0.0,1.0, 0.0, 0.0) glutSolidCone(0.08,0.5,10,2) glColor3f(1.0, 1.0, 1.0) func renderBitmapString x,y,z,font,string glRasterPos3f(x, y,z) for c in string glutBitmapCharacter(font,ascii(c)) next func computePos deltaMove x += deltaMove * lx * 0.1 z += deltaMove * lz * 0.1 func renderScene if deltaMove computePos(deltaMove) ok // Clear Color and Depth Buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) // Reset transformations glLoadIdentity() // Set the camera gluLookAt( x, 1.0, z, x+lx, 1.0, z+lz, 0.0, 1.0, 0.0) (continues on next page) 58.13. Using Fonts 743
783.
Ring Documentation, Release1.16 (continued from previous page) // Draw ground glColor3f(0.9, 0.9, 0.9) glBegin(GL_QUADS) glVertex3f(-100.0, 0.0, -100.0) glVertex3f(-100.0, 0.0, 100.0) glVertex3f( 100.0, 0.0, 100.0) glVertex3f( 100.0, 0.0, -100.0) glEnd() // Draw 36 SnowMen for i = -3 to 2 for j = -3 to 2 glPushMatrix() glTranslatef(i*10.0, 0.0, j * 10.0) drawSnowMan() number = (i+3)*6+(j+3) renderBitmapString(0.0, 0.5, 0.0,font ,""+number) glPopMatrix() next next glutSwapBuffers() // ----------------------------------- // KEYBOARD // ----------------------------------- func processNormalKeys key = glutEventKey() xx = glutEventX() yy = glutEventY() switch key on 27 glutDestroyMenu(mainMenu) glutDestroyMenu(fillMenu) glutDestroyMenu(colorMenu) glutDestroyMenu(fontMenu) Shutdown() off func pressKey key = glutEventKey() xx = glutEventX() yy = glutEventY() switch key on GLUT_KEY_UP deltaMove = 0.5 on GLUT_KEY_DOWN deltaMove = -0.5 off (continues on next page) 58.13. Using Fonts 744
784.
Ring Documentation, Release1.16 (continued from previous page) func releaseKey key = glutEventKey() switch key on GLUT_KEY_UP deltaMove = 0 on GLUT_KEY_DOWN deltaMove = 0 off // ----------------------------------- // MOUSE // ----------------------------------- func mouseMove xx = glutEventX() yy = glutEventY() // this will only be true when the left button is down if xOrigin >= 0 // update deltaAngle deltaAngle = (xx - xOrigin) * 0.001 // update camera's direction lx = sin(angle + deltaAngle) lz = -cos(angle + deltaAngle) ok func mouseButton button = glutEventButton() state = glutEventState() xx = glutEventX() yy = glutEventY() // only start motion if the left button is pressed if button = GLUT_LEFT_BUTTON // when the button is released if state = GLUT_UP angle += deltaAngle xOrigin = -1 else // state = GLUT_DOWN xOrigin = xx ok ok // ----------------------------------- // MENUS // ----------------------------------- (continues on next page) 58.13. Using Fonts 745
785.
Ring Documentation, Release1.16 (continued from previous page) func processMenuStatus status = glutEventStatus() if status = GLUT_MENU_IN_USE menuFlag = 1 else menuFlag = 0 ok func processMainMenu // nothing to do in here // all actions are for submenus func processFillMenu option = glutEventValue() switch option on C_FILL glPolygonMode(GL_FRONT, GL_FILL) on C_LINE glPolygonMode(GL_FRONT, GL_LINE) off func processFontMenu option = glutEventValue() switch (option) { on C_INT_GLUT_BITMAP_8_BY_13 font = GLUT_BITMAP_8_BY_13 on C_INT_GLUT_BITMAP_9_BY_15 font = GLUT_BITMAP_9_BY_15 on C_INT_GLUT_BITMAP_TIMES_ROMAN_10 font = GLUT_BITMAP_TIMES_ROMAN_10 on C_INT_GLUT_BITMAP_TIMES_ROMAN_24 font = GLUT_BITMAP_TIMES_ROMAN_24 on C_INT_GLUT_BITMAP_HELVETICA_10 font = GLUT_BITMAP_HELVETICA_10 on C_INT_GLUT_BITMAP_HELVETICA_12 font = GLUT_BITMAP_HELVETICA_12 on C_INT_GLUT_BITMAP_HELVETICA_18 font = GLUT_BITMAP_HELVETICA_18 off func processColorMenu option = glutEventValue() switch option on C_RED (continues on next page) 58.13. Using Fonts 746
786.
Ring Documentation, Release1.16 (continued from previous page) red = 1.0 green = 0.0 blue = 0.0 on C_GREEN red = 0.0 green = 1.0 blue = 0.0 on C_BLUE red = 0.0 green = 0.0 blue = 1.0 on C_ORANGE red = 1.0 green = 0.5 blue = 0.5 off func createPopupMenus fontMenu = glutCreateMenu(:processFontMenu) glutAddMenuEntry("BITMAP_8_BY_13 ",C_INT_GLUT_BITMAP_8_BY_13 ) glutAddMenuEntry("BITMAP_9_BY_15",C_INT_GLUT_BITMAP_9_BY_15 ) glutAddMenuEntry("BITMAP_TIMES_ROMAN_10 ",C_INT_GLUT_BITMAP_TIMES_ROMAN_10 ) glutAddMenuEntry("BITMAP_TIMES_ROMAN_24",C_INT_GLUT_BITMAP_TIMES_ROMAN_24 ) glutAddMenuEntry("BITMAP_HELVETICA_10 ",C_INT_GLUT_BITMAP_HELVETICA_10 ) glutAddMenuEntry("BITMAP_HELVETICA_12",C_INT_GLUT_BITMAP_HELVETICA_12 ) glutAddMenuEntry("BITMAP_HELVETICA_18",C_INT_GLUT_BITMAP_HELVETICA_18 ) fillMenu = glutCreateMenu(:processFillMenu) glutAddMenuEntry("Fill",C_FILL) glutAddMenuEntry("Line",C_LINE) colorMenu = glutCreateMenu(:processColorMenu) glutAddMenuEntry("Red",C_RED); glutAddMenuEntry("Blue",C_BLUE); glutAddMenuEntry("Green",C_GREEN); glutAddMenuEntry("Orange",C_ORANGE); mainMenu = glutCreateMenu(:processMainMenu) glutAddSubMenu("Polygon Mode", fillMenu) glutAddSubMenu("Color", colorMenu) glutAddSubMenu("Font",fontMenu) // attach the menu to the right button glutAttachMenu(GLUT_RIGHT_BUTTON) // this will allow us to know if the menu is active glutMenuStatusFunc(:processMenuStatus) // ----------------------------------- // MAIN // ----------------------------------- (continues on next page) 58.13. Using Fonts 747
787.
Ring Documentation, Release1.16 (continued from previous page) func main // init GLUT and create window glutInit() glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA) glutInitWindowPosition(100,100) glutInitWindowSize(320,320) glutCreateWindow("RingFreeGLUT - Test 11") // register callbacks glutDisplayFunc(:renderScene) glutReshapeFunc(:changeSize) glutIdleFunc(:renderScene) glutIgnoreKeyRepeat(1) glutKeyboardFunc(:processNormalKeys) glutSpecialFunc(:pressKey) glutSpecialUpFunc(:releaseKey) // here are the two new functions glutMouseFunc(:mouseButton) glutMotionFunc(:mouseMove) // OpenGL init glEnable(GL_DEPTH_TEST) glEnable(GL_CULL_FACE) // init Menus createPopupMenus() // enter GLUT event processing cycle glutMainLoop() Screen Shot 58.13. Using Fonts 748
788.
Ring Documentation, Release1.16 58.14 Frames Per Second Example load "freeglut.ring" load "opengl21lib.ring" // angle of rotation for the camera direction angle = 0.0 // actual vector representing the camera's direction lx=0.0 lz=-1.0 // XZ position of the camera x=0.0 z=5.0 // the key states. These variables will be zero //when no key is being presses deltaAngle = 0.0 deltaMove = 0 xOrigin = -1 // Constant definitions for Menus C_RED = 1 C_GREEN = 2 C_BLUE = 3 C_ORANGE = 4 C_FILL = 5 C_LINE = 6 // Pop up menu identifiers fillMenu=NULL fontMenu=NULL mainMenu=NULL colorMenu=NULL // color for the nose red = 1.0 blue=0.5 green=0.5 // scale of snowman scale = 1.0 // menu status menuFlag = 0 // default font font = GLUT_BITMAP_TIMES_ROMAN_24 C_INT_GLUT_BITMAP_8_BY_13 = 7 C_INT_GLUT_BITMAP_9_BY_15 = 8 C_INT_GLUT_BITMAP_TIMES_ROMAN_10 = 9 C_INT_GLUT_BITMAP_TIMES_ROMAN_24 = 10 C_INT_GLUT_BITMAP_HELVETICA_10 = 11 C_INT_GLUT_BITMAP_HELVETICA_12 = 12 (continues on next page) 58.14. Frames Per Second 749
789.
Ring Documentation, Release1.16 (continued from previous page) C_INT_GLUT_BITMAP_HELVETICA_18 = 13 // width and height of the window h = 0 w = 0 // variables to compute frames per second frame=0 time=0 timebase=0 s = "" func changeSize w = glutEventWidth() h = glutEventHeight() // Prevent a divide by zero, when window is too short // (you cant make a window of zero width). if h = 0 h = 1 ok ratio = w * 1.0 / h // Use the Projection Matrix glMatrixMode(GL_PROJECTION) // Reset Matrix glLoadIdentity() // Set the viewport to be the entire window glViewport(0, 0, w, h) // Set the correct perspective. gluPerspective(45.0, ratio, 0.1, 100.0) // Get Back to the Modelview glMatrixMode(GL_MODELVIEW) func drawSnowMan glScalef(scale, scale, scale) glColor3f(1.0, 1.0, 1.0) // Draw Body glTranslatef(0.0 ,0.75, 0.0) glutSolidSphere(0.75,20,20) // Draw Head glTranslatef(0.0, 1.0, 0.0) glutSolidSphere(0.25,20,20) // Draw Eyes glPushMatrix() glColor3f(0.0,0.0,0.0) glTranslatef(0.05, 0.10, 0.18) glutSolidSphere(0.05,10,10) (continues on next page) 58.14. Frames Per Second 750
790.
Ring Documentation, Release1.16 (continued from previous page) glTranslatef(-0.1, 0.0, 0.0) glutSolidSphere(0.05,10,10) glPopMatrix() // Draw Nose glColor3f(red, green, blue) glRotatef(0.0,1.0, 0.0, 0.0) glutSolidCone(0.08,0.5,10,2) glColor3f(1.0, 1.0, 1.0) func renderBitmapString x,y,z,font,string glRasterPos3f(x, y,z) for c in string glutBitmapCharacter(font,ascii(c)) next func renderStrokeFontString x,y,z,font,string glPushMatrix() glTranslatef(x, y,z) glScalef(0.002, 0.002, 0.002) for c in string glutStrokeCharacter(font, Ascii(c)); next glPopMatrix() func restorePerspectiveProjection glMatrixMode(GL_PROJECTION) // restore previous projection matrix glPopMatrix() // get back to modelview mode glMatrixMode(GL_MODELVIEW) func setOrthographicProjection // switch to projection mode glMatrixMode(GL_PROJECTION) // save previous matrix which contains the //settings for the perspective projection glPushMatrix() // reset matrix glLoadIdentity() // set a 2D orthographic projection gluOrtho2D(0, w, h, 0) // switch back to modelview mode glMatrixMode(GL_MODELVIEW) (continues on next page) 58.14. Frames Per Second 751
791.
Ring Documentation, Release1.16 (continued from previous page) func computePos deltaMove x += deltaMove * lx * 0.1 z += deltaMove * lz * 0.1 func renderScene if deltaMove computePos(deltaMove) ok // Clear Color and Depth Buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) // Reset transformations glLoadIdentity() // Set the camera gluLookAt( x, 1.0, z, x+lx, 1.0, z+lz, 0.0, 1.0, 0.0) // Draw ground glColor3f(0.9, 0.9, 0.9) glBegin(GL_QUADS) glVertex3f(-100.0, 0.0, -100.0) glVertex3f(-100.0, 0.0, 100.0) glVertex3f( 100.0, 0.0, 100.0) glVertex3f( 100.0, 0.0, -100.0) glEnd() // Draw 9 SnowMen for i = -3 to -1 for j = -3 to -1 glPushMatrix() glTranslatef(i*10.0, 0.0, j * 10.0) drawSnowMan() number = (i+3)*3+(j+3) renderBitmapString(0.0, 0.5, 0.0,font ,""+number) glPopMatrix() next next // Code to compute frames per second frame++ time=glutGet(GLUT_ELAPSED_TIME) if time - timebase > 1000 s = "RingFreeGLUT - FPS: " + (frame*1000.0/(time-timebase)) timebase = time frame = 0 ok // Code to display a string (fps) with bitmap fonts setOrthographicProjection() (continues on next page) 58.14. Frames Per Second 752
792.
Ring Documentation, Release1.16 (continued from previous page) glPushMatrix() glLoadIdentity() renderBitmapString(5,30,0,GLUT_BITMAP_HELVETICA_18,s) glPopMatrix() restorePerspectiveProjection() glutSwapBuffers() // ----------------------------------- // KEYBOARD // ----------------------------------- func processNormalKeys key = glutEventKey() xx = glutEventX() yy = glutEventY() switch key on 27 glutDestroyMenu(mainMenu) glutDestroyMenu(fillMenu) glutDestroyMenu(colorMenu) glutDestroyMenu(fontMenu) Shutdown() off func pressKey key = glutEventKey() xx = glutEventX() yy = glutEventY() switch key on GLUT_KEY_UP deltaMove = 0.5 on GLUT_KEY_DOWN deltaMove = -0.5 off func releaseKey key = glutEventKey() switch key on GLUT_KEY_UP deltaMove = 0 on GLUT_KEY_DOWN deltaMove = 0 off // ----------------------------------- (continues on next page) 58.14. Frames Per Second 753
793.
Ring Documentation, Release1.16 (continued from previous page) // MOUSE // ----------------------------------- func mouseMove xx = glutEventX() yy = glutEventY() // this will only be true when the left button is down if xOrigin >= 0 // update deltaAngle deltaAngle = (xx - xOrigin) * 0.001 // update camera's direction lx = sin(angle + deltaAngle) lz = -cos(angle + deltaAngle) ok func mouseButton button = glutEventButton() state = glutEventState() xx = glutEventX() yy = glutEventY() // only start motion if the left button is pressed if button = GLUT_LEFT_BUTTON // when the button is released if state = GLUT_UP angle += deltaAngle xOrigin = -1 else // state = GLUT_DOWN xOrigin = xx ok ok // ----------------------------------- // MENUS // ----------------------------------- func processMenuStatus status = glutEventStatus() if status = GLUT_MENU_IN_USE menuFlag = 1 else menuFlag = 0 ok func processMainMenu // nothing to do in here (continues on next page) 58.14. Frames Per Second 754
794.
Ring Documentation, Release1.16 (continued from previous page) // all actions are for submenus func processFillMenu option = glutEventValue() switch option on C_FILL glPolygonMode(GL_FRONT, GL_FILL) on C_LINE glPolygonMode(GL_FRONT, GL_LINE) off func processFontMenu option = glutEventValue() switch (option) { on C_INT_GLUT_BITMAP_8_BY_13 font = GLUT_BITMAP_8_BY_13 on C_INT_GLUT_BITMAP_9_BY_15 font = GLUT_BITMAP_9_BY_15 on C_INT_GLUT_BITMAP_TIMES_ROMAN_10 font = GLUT_BITMAP_TIMES_ROMAN_10 on C_INT_GLUT_BITMAP_TIMES_ROMAN_24 font = GLUT_BITMAP_TIMES_ROMAN_24 on C_INT_GLUT_BITMAP_HELVETICA_10 font = GLUT_BITMAP_HELVETICA_10 on C_INT_GLUT_BITMAP_HELVETICA_12 font = GLUT_BITMAP_HELVETICA_12 on C_INT_GLUT_BITMAP_HELVETICA_18 font = GLUT_BITMAP_HELVETICA_18 off func processColorMenu option = glutEventValue() switch option on C_RED red = 1.0 green = 0.0 blue = 0.0 on C_GREEN red = 0.0 green = 1.0 blue = 0.0 on C_BLUE red = 0.0 green = 0.0 blue = 1.0 on C_ORANGE red = 1.0 green = 0.5 (continues on next page) 58.14. Frames Per Second 755
795.
Ring Documentation, Release1.16 (continued from previous page) blue = 0.5 off func createPopupMenus fontMenu = glutCreateMenu(:processFontMenu) glutAddMenuEntry("BITMAP_8_BY_13 ",C_INT_GLUT_BITMAP_8_BY_13 ) glutAddMenuEntry("BITMAP_9_BY_15",C_INT_GLUT_BITMAP_9_BY_15 ) glutAddMenuEntry("BITMAP_TIMES_ROMAN_10 ",C_INT_GLUT_BITMAP_TIMES_ROMAN_10 ) glutAddMenuEntry("BITMAP_TIMES_ROMAN_24",C_INT_GLUT_BITMAP_TIMES_ROMAN_24 ) glutAddMenuEntry("BITMAP_HELVETICA_10 ",C_INT_GLUT_BITMAP_HELVETICA_10 ) glutAddMenuEntry("BITMAP_HELVETICA_12",C_INT_GLUT_BITMAP_HELVETICA_12 ) glutAddMenuEntry("BITMAP_HELVETICA_18",C_INT_GLUT_BITMAP_HELVETICA_18 ) fillMenu = glutCreateMenu(:processFillMenu) glutAddMenuEntry("Fill",C_FILL) glutAddMenuEntry("Line",C_LINE) colorMenu = glutCreateMenu(:processColorMenu) glutAddMenuEntry("Red",C_RED); glutAddMenuEntry("Blue",C_BLUE); glutAddMenuEntry("Green",C_GREEN); glutAddMenuEntry("Orange",C_ORANGE); mainMenu = glutCreateMenu(:processMainMenu) glutAddSubMenu("Polygon Mode", fillMenu) glutAddSubMenu("Color", colorMenu) glutAddSubMenu("Font",fontMenu) // attach the menu to the right button glutAttachMenu(GLUT_RIGHT_BUTTON) // this will allow us to know if the menu is active glutMenuStatusFunc(:processMenuStatus) // ----------------------------------- // MAIN // ----------------------------------- func main // init GLUT and create window glutInit() glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA) glutInitWindowPosition(100,100) glutInitWindowSize(320,320) glutCreateWindow("RingFreeGLUT - Test - 9 SnowMan") // register callbacks glutDisplayFunc(:renderScene) glutReshapeFunc(:changeSize) glutIdleFunc(:renderScene) (continues on next page) 58.14. Frames Per Second 756
796.
Ring Documentation, Release1.16 (continued from previous page) glutIgnoreKeyRepeat(1) glutKeyboardFunc(:processNormalKeys) glutSpecialFunc(:pressKey) glutSpecialUpFunc(:releaseKey) // here are the two new functions glutMouseFunc(:mouseButton) glutMotionFunc(:mouseMove) // OpenGL init glEnable(GL_DEPTH_TEST) glEnable(GL_CULL_FACE) // init Menus createPopupMenus() // enter GLUT event processing cycle glutMainLoop() Screen Shots: The First screen shot The Second screen shot 58.14. Frames Per Second 757
797.
Ring Documentation, Release1.16 58.15 Make a Cube using RingOpenGL and RingFreeGLUT Example: load "freeglut.ring" load "opengl21lib.ring" // ---------------------------------------------------------- // Global Variables // ---------------------------------------------------------- rotate_y=0 rotate_x=0 // ---------------------------------------------------------- // display() Callback function // ---------------------------------------------------------- func display // Clear screen and Z-buffer glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) // Reset transformations glLoadIdentity() // Rotate when user changes rotate_x and rotate_y glRotatef( rotate_x, 1.0, 0.0, 0.0 ) glRotatef( rotate_y, 0.0, 1.0, 0.0 ) //Multi-colored side - FRONT glBegin(GL_POLYGON) glColor3f( 1.0, 0.0, 0.0 ) glVertex3f( 0.5, -0.5, -0.5 ) # P1 is red (continues on next page) 58.15. Make a Cube using RingOpenGL and RingFreeGLUT 758
798.
Ring Documentation, Release1.16 (continued from previous page) glColor3f( 0.0, 1.0, 0.0 ) glVertex3f( 0.5, 0.5, -0.5 ) # P2 is green glColor3f( 0.0, 0.0, 1.0 ) glVertex3f( -0.5, 0.5, -0.5 ) # P3 is blue glColor3f( 1.0, 0.0, 1.0 ) glVertex3f( -0.5, -0.5, -0.5 ) # P4 is purple glEnd() // White side - BACK glBegin(GL_POLYGON) glColor3f( 1.0, 1.0, 1.0 ) glVertex3f( 0.5, -0.5, 0.5 ) glVertex3f( 0.5, 0.5, 0.5 ) glVertex3f( -0.5, 0.5, 0.5 ) glVertex3f( -0.5, -0.5, 0.5 ) glEnd() // Purple side - RIGHT glBegin(GL_POLYGON) glColor3f( 1.0, 0.0, 1.0 ) glVertex3f( 0.5, -0.5, -0.5 ) glVertex3f( 0.5, 0.5, -0.5 ) glVertex3f( 0.5, 0.5, 0.5 ) glVertex3f( 0.5, -0.5, 0.5 ) glEnd() // Green side - LEFT glBegin(GL_POLYGON) glColor3f( 0.0, 1.0, 0.0 ) glVertex3f( -0.5, -0.5, 0.5 ) glVertex3f( -0.5, 0.5, 0.5 ) glVertex3f( -0.5, 0.5, -0.5 ) glVertex3f( -0.5, -0.5, -0.5 ) glEnd() // Blue side - TOP glBegin(GL_POLYGON) glColor3f( 0.0, 0.0, 1.0 ) glVertex3f( 0.5, 0.5, 0.5 ) glVertex3f( 0.5, 0.5, -0.5 ) glVertex3f( -0.5, 0.5, -0.5 ) glVertex3f( -0.5, 0.5, 0.5 ) glEnd() // Red side - BOTTOM glBegin(GL_POLYGON) glColor3f( 1.0, 0.0, 0.0 ) glVertex3f( 0.5, -0.5, -0.5 ) glVertex3f( 0.5, -0.5, 0.5 ) glVertex3f( -0.5, -0.5, 0.5 ) glVertex3f( -0.5, -0.5, -0.5 ) glEnd() glFlush() glutSwapBuffers() // ---------------------------------------------------------- // specialKeys() Callback Function (continues on next page) 58.15. Make a Cube using RingOpenGL and RingFreeGLUT 759
799.
Ring Documentation, Release1.16 (continued from previous page) // ---------------------------------------------------------- func specialKeys key = glutEventKey() // Right arrow - increase rotation by 5 degree switch Key on GLUT_KEY_RIGHT rotate_y += 5 // Left arrow - decrease rotation by 5 degree on GLUT_KEY_LEFT rotate_y -= 5 on GLUT_KEY_UP rotate_x += 5 on GLUT_KEY_DOWN rotate_x -= 5 off // Request display update glutPostRedisplay() // ---------------------------------------------------------- // main() function // ---------------------------------------------------------- func main // Initialize GLUT and process user parameters glutInit() // Request double buffered true color window with Z-buffer glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH) // Create window glutCreateWindow("Awesome Cube") // Enable Z-buffer depth test glEnable(GL_DEPTH_TEST) // Callback functions glutDisplayFunc(:display) glutSpecialFunc(:specialKeys) // Pass control to GLUT for events glutMainLoop() // Return to OS Screen Shot: 58.15. Make a Cube using RingOpenGL and RingFreeGLUT 760
CHAPTER FIFTYNINE USING RINGOPENGL ANDRINGALLEGRO FOR 3D GRAPHICS In this chapter we will learn about using RingOpenGL and RingAllegro 59.1 3D Cube and Texture Source Code: # Load Libraries load "gamelib.ring" # RingAllegro Library load "opengl21lib.ring" # RingOpenGL Library #============================================================== # To Support MacOS X al_run_main() func al_game_start # Called by al_run_main() main() # Now we call our main function #============================================================== func main new GraphicsApp { start() } class GraphicsApp from GraphicsAppBase TITLE = "Ring Cube" bitmap texture xrot = 0.0 yrot = 0.0 zrot = 0.0 func loadresources bitmap = al_load_bitmap("ring.bmp") texture = al_get_opengl_texture(bitmap) func destroyResources al_destroy_bitmap(bitmap) (continues on next page) 762
802.
Ring Documentation, Release1.16 (continued from previous page) func drawScene w = 800 h = 600 ratio = w / h glViewport(0, 0, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(45,ratio,1,100) glMatrixMode(GL_MODELVIEW) glLoadIdentity() glEnable(GL_TEXTURE_2D) glShadeModel(GL_SMOOTH) glClearColor(0.0, 0.0, 0.0, 0.5) glClearDepth(1.0) glEnable(GL_DEPTH_TEST) glEnable(GL_CULL_FACE) glDepthFunc(GL_LEQUAL) glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glLoadIdentity() glTranslatef(0.0,0.0,-5.0) glRotatef(xrot,1.0,0.0,0.0) glRotatef(yrot,0.0,1.0,0.0) glRotatef(zrot,0.0,0.0,1.0) glBindTexture(GL_TEXTURE_2D, texture) glBegin(GL_QUADS) // Front Face glTexCoord2f(0.0, 0.0) glVertex3f(-1.0, -1.0, 1.0) glTexCoord2f(1.0, 0.0) glVertex3f( 1.0, -1.0, 1.0) glTexCoord2f(1.0, 1.0) glVertex3f( 1.0, 1.0, 1.0) glTexCoord2f(0.0, 1.0) glVertex3f(-1.0, 1.0, 1.0) // Back Face glTexCoord2f(1.0, 0.0) glVertex3f(-1.0, -1.0, -1.0) glTexCoord2f(1.0, 1.0) glVertex3f(-1.0, 1.0, -1.0) glTexCoord2f(0.0, 1.0) glVertex3f( 1.0, 1.0, -1.0) glTexCoord2f(0.0, 0.0) glVertex3f( 1.0, -1.0, -1.0) // Top Face glTexCoord2f(0.0, 1.0) glVertex3f(-1.0, 1.0, -1.0) glTexCoord2f(0.0, 0.0) glVertex3f(-1.0, 1.0, 1.0) glTexCoord2f(1.0, 0.0) glVertex3f( 1.0, 1.0, 1.0) glTexCoord2f(1.0, 1.0) glVertex3f( 1.0, 1.0, -1.0) // Bottom Face glTexCoord2f(1.0, 1.0) glVertex3f(-1.0, -1.0, -1.0) glTexCoord2f(0.0, 1.0) glVertex3f( 1.0, -1.0, -1.0) glTexCoord2f(0.0, 0.0) glVertex3f( 1.0, -1.0, 1.0) glTexCoord2f(1.0, 0.0) glVertex3f(-1.0, -1.0, 1.0) // Right face glTexCoord2f(1.0, 0.0) glVertex3f( 1.0, -1.0, -1.0) glTexCoord2f(1.0, 1.0) glVertex3f( 1.0, 1.0, -1.0) (continues on next page) 59.1. 3D Cube and Texture 763
Ring Documentation, Release1.16 (continued from previous page) al_start_timer(timer) al_install_mouse() al_register_event_source(event_queue, al_get_mouse_event_source()) al_install_keyboard() al_register_event_source(event_queue, al_get_keyboard_event_source()) func eventsLoop while true al_init_timeout(timeout, 0.06) al_wait_for_event_until(event_queue, ev, timeout) switch al_get_allegro_event_type(ev) on ALLEGRO_EVENT_DISPLAY_CLOSE exit on ALLEGRO_EVENT_TIMER redraw = true on ALLEGRO_EVENT_MOUSE_AXES mouse_x = al_get_allegro_event_mouse_x(ev) mouse_y = al_get_allegro_event_mouse_y(ev) on ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY mouse_x = al_get_allegro_event_mouse_x(ev) mouse_y = al_get_allegro_event_mouse_y(ev) on ALLEGRO_EVENT_MOUSE_BUTTON_UP exit on ALLEGRO_EVENT_KEY_DOWN switch al_get_allegro_event_keyboard_keycode(ev) on ALLEGRO_KEY_UP key[KEY_UP] = true on ALLEGRO_KEY_DOWN key[KEY_DOWN] = true on ALLEGRO_KEY_LEFT key[KEY_LEFT] = true on ALLEGRO_KEY_RIGHT key[KEY_RIGHT] = true off on ALLEGRO_EVENT_KEY_UP switch al_get_allegro_event_keyboard_keycode(ev) on ALLEGRO_KEY_UP key[KEY_UP] = false on ALLEGRO_KEY_DOWN key[KEY_DOWN] = false on ALLEGRO_KEY_LEFT key[KEY_LEFT] = false on ALLEGRO_KEY_RIGHT key[KEY_RIGHT] = false on ALLEGRO_KEY_ESCAPE exit off off if redraw and al_is_event_queue_empty(event_queue) redraw = false drawScene() al_flip_display() ok callgc() (continues on next page) 59.1. 3D Cube and Texture 765
805.
Ring Documentation, Release1.16 (continued from previous page) end func destroy destroyResources() al_destroy_timer(timer) al_destroy_allegro_event(ev) al_destroy_allegro_timeout(timeout) al_destroy_event_queue(event_queue) al_destroy_display(display) al_exit() func loadresources func drawScene func destroyResources Screen Shot: 59.2 Many Cubes Source Code: # Load Libraries load "gamelib.ring" # RingAllegro Library load "opengl21lib.ring" # RingOpenGL Library #============================================================== # To Support MacOS X al_run_main() (continues on next page) 59.2. Many Cubes 766
806.
Ring Documentation, Release1.16 (continued from previous page) func al_game_start # Called by al_run_main() main() # Now we call our main function #============================================================== func main new GraphicsApp { start() } class GraphicsApp from GraphicsAppBase TITLE = "Many Cubes" bitmap bitmap2 bitmap3 texture texture2 texture3 fps = 120 xrot = 0.0 yrot = 0.0 zrot = 0.0 nPerspective = 100 func loadresources bitmap = al_load_bitmap("sky1.jpg") texture = al_get_opengl_texture(bitmap) bitmap2 = al_load_bitmap("sky2.jpg") texture2 = al_get_opengl_texture(bitmap2) bitmap3 = al_load_bitmap("sky3.jpg") texture3 = al_get_opengl_texture(bitmap3) func destroyResources al_destroy_bitmap(bitmap) al_destroy_bitmap(bitmap2) al_destroy_bitmap(bitmap3) func drawScene prepare() cubes() rotate() func Prepare w = 800 h = 600 ratio = w / h glViewport(0, 0, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(-nPerspective,ratio,1,nPerspective) glMatrixMode(GL_MODELVIEW) (continues on next page) 59.2. Many Cubes 767
807.
Ring Documentation, Release1.16 (continued from previous page) glLoadIdentity() glEnable(GL_TEXTURE_2D) glShadeModel(GL_SMOOTH) glClearColor(0.0, 0.0, 0.0, 0.5) glClearDepth(1.0) glEnable(GL_DEPTH_TEST) glEnable(GL_CULL_FACE) glDepthFunc(GL_LEQUAL) glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) func Cubes cube(5,-3.4,-5,:sky1) cube(0,-3,-5,:sky1) cube(-5,-3,-5,:sky1) cube(5,0.5,-5,:sky2) cube(0,0.5,-5,:sky2) cube(-5,0.5,-5,:sky2) cube(5,4,-5,:sky3) cube(0,4,-5,:sky3) cube(-5,4,-5,:sky3) func Rotate xrot += 0.3 * 5 yrot += 0.2 * 5 zrot += 0.4 * 5 nPerspective += 0.5 func cube(x,y,z,nTexture) glLoadIdentity() glTranslatef(x,y,z) glRotatef(xrot,1.0,0.0,0.0) glRotatef(yrot,0.0,1.0,0.0) glRotatef(zrot,0.0,0.0,1.0) drawcube(nTexture) func drawcube(cTexture) switch cTexture on :sky1 glBindTexture(GL_TEXTURE_2D, texture) on :sky2 glBindTexture(GL_TEXTURE_2D, texture2) on :sky3 glBindTexture(GL_TEXTURE_2D, texture3) off glBegin(GL_QUADS) // Front Face glTexCoord2f(0.0, 0.0) glVertex3f(-1.0, -1.0, 1.0) glTexCoord2f(1.0, 0.0) glVertex3f( 1.0, -1.0, 1.0) glTexCoord2f(1.0, 1.0) glVertex3f( 1.0, 1.0, 1.0) glTexCoord2f(0.0, 1.0) glVertex3f(-1.0, 1.0, 1.0) // Back Face glTexCoord2f(1.0, 0.0) glVertex3f(-1.0, -1.0, -1.0) (continues on next page) 59.2. Many Cubes 768
Ring Documentation, Release1.16 (continued from previous page) al_init_image_addon() al_set_new_display_flags(ALLEGRO_OPENGL) display = al_create_display(SCREEN_W,SCREEN_H) al_set_Window_title(display,TITLE) al_clear_to_color(al_map_rgb(0,0,0)) event_queue = al_create_event_queue() al_register_event_source(event_queue, al_get_display_event_source(display)) ev = al_new_allegro_event() timeout = al_new_allegro_timeout() al_init_timeout(timeout, 0.06) timer = al_create_timer(1.0 / FPS) al_register_event_source(event_queue, al_get_timer_event_source(timer)) al_start_timer(timer) al_install_mouse() al_register_event_source(event_queue, al_get_mouse_event_source()) al_install_keyboard() al_register_event_source(event_queue, al_get_keyboard_event_source()) func eventsLoop while true al_init_timeout(timeout, 0.06) al_wait_for_event_until(event_queue, ev, timeout) switch al_get_allegro_event_type(ev) on ALLEGRO_EVENT_DISPLAY_CLOSE exit on ALLEGRO_EVENT_TIMER redraw = true on ALLEGRO_EVENT_MOUSE_AXES mouse_x = al_get_allegro_event_mouse_x(ev) mouse_y = al_get_allegro_event_mouse_y(ev) on ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY mouse_x = al_get_allegro_event_mouse_x(ev) mouse_y = al_get_allegro_event_mouse_y(ev) on ALLEGRO_EVENT_MOUSE_BUTTON_UP exit on ALLEGRO_EVENT_KEY_DOWN switch al_get_allegro_event_keyboard_keycode(ev) on ALLEGRO_KEY_UP key[KEY_UP] = true on ALLEGRO_KEY_DOWN key[KEY_DOWN] = true on ALLEGRO_KEY_LEFT key[KEY_LEFT] = true on ALLEGRO_KEY_RIGHT key[KEY_RIGHT] = true off on ALLEGRO_EVENT_KEY_UP switch al_get_allegro_event_keyboard_keycode(ev) on ALLEGRO_KEY_UP key[KEY_UP] = false on ALLEGRO_KEY_DOWN key[KEY_DOWN] = false (continues on next page) 59.2. Many Cubes 770
810.
Ring Documentation, Release1.16 (continued from previous page) on ALLEGRO_KEY_LEFT key[KEY_LEFT] = false on ALLEGRO_KEY_RIGHT key[KEY_RIGHT] = false on ALLEGRO_KEY_ESCAPE exit off off if redraw and al_is_event_queue_empty(event_queue) redraw = false drawScene() al_flip_display() ok callgc() end func destroy destroyResources() al_destroy_timer(timer) al_destroy_allegro_event(ev) al_destroy_allegro_timeout(timeout) al_destroy_event_queue(event_queue) al_destroy_display(display) al_exit() func loadresources func drawScene func destroyResources Screen Shot: 59.2. Many Cubes 771
811.
Ring Documentation, Release1.16 59.3 TicTacToe 3D Game Source Code: # Load Libraries load "gamelib.ring" # RingAllegro Library load "opengl21lib.ring" # RingOpenGL Library #============================================================== # To Support MacOS X al_run_main() func al_game_start # Called by al_run_main() main() # Now we call our main function #============================================================== func main new TicTacToe3D { start() } class TicTacToe3D from GameLogic (continues on next page) 59.3. TicTacToe 3D Game 772
812.
Ring Documentation, Release1.16 (continued from previous page) FPS = 60 TITLE = "TicTacToe 3D" oBackground = new GameBackground oGameSound = new GameSound oGameCube = new GameCube oGameOver = new GameOver oGameInterface = new GameInterface func loadresources oGameOver.loadresources() oGameSound.loadresources() oBackGround.loadresources() oGameCube.loadresources() func destroyResources oGameOver.destroyResources() oGameSound.destroyResources() oBackGround.destroyResources() oGameCube.destroyResources() func drawScene oBackground.update() oGameInterface.update(self) func MouseClickEvent oGameInterface.MouseClickEvent(self) class GameInterface func Update oGame prepare() cubes(oGame) func Prepare w = 1024 h = 768 ratio = w / h glViewport(0, 0, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(-120,ratio,1,120) glMatrixMode(GL_MODELVIEW) glLoadIdentity() glEnable(GL_TEXTURE_2D) glShadeModel(GL_SMOOTH) glClearColor(0.0, 0.0, 0.0, 0.5) glClearDepth(1.0) glEnable(GL_DEPTH_TEST) glEnable(GL_CULL_FACE) glDepthFunc(GL_LEQUAL) glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) func Cubes oGame oGame.oGameCube { aGameMap = oGame.aGameMap cube( 5 , -3 , -5 , aGameMap[1][1] ) (continues on next page) 59.3. TicTacToe 3D Game 773
813.
Ring Documentation, Release1.16 (continued from previous page) cube( 0 , -3 , -5 , aGameMap[1][2] ) cube( -5 , -3 , -5 , aGameMap[1][3] ) cube( 5 , 1 , -5 , aGameMap[2][1] ) cube( 0 , 1 , -5 , aGameMap[2][2] ) cube( -5 , 1 , -5 , aGameMap[2][3] ) cube( 5 , 5 , -5 , aGameMap[3][1] ) cube( 0 , 5 , -5 , aGameMap[3][2] ) cube( -5 , 5 , -5 , aGameMap[3][3] ) rotate() } func MouseClickEvent oGame oGame { aBtn = Point2Button(Mouse_X,Mouse_Y) nRow = aBtn[1] nCol = aBtn[2] if nRow != 0 and nCol != 0 if aGameMap[nRow][nCol] = :n aGameMap[nRow][nCol] = cActivePlayer ChangeActivePlayer() CheckGameOver() ok ok } Class GameLogic from GraphicsAppBase aGameMap = [ [ :n , :n , :n ] , [ :n , :n , :n ] , [ :n , :n , :n ] ] aGameButtons = [ # x1,y1,x2,y2 [176,88,375,261], # [1,1] [423,88,591,261], # [1,2] [645,88,876,261], # [1,3] [176,282,375,428], # [2,1] [423,282,591,428], # [2,2] [645,282,876,428], # [2,3] [176,454,375,678], # [3,1] [423,454,591,678], # [3,2] [645,454,876,678] # [3,3] ] cActivePlayer = :x func point2button x,y nRow = 0 nCol = 0 for t = 1 to len(aGameButtons) rect = aGameButtons[t] if x >= rect[1] and x <= rect[3] and y >= rect[2] and y <= rect[4] switch t on 1 nRow = 1 nCol = 1 on 2 nRow = 1 nCol = 2 (continues on next page) 59.3. TicTacToe 3D Game 774
814.
Ring Documentation, Release1.16 (continued from previous page) on 3 nRow = 1 nCol = 3 on 4 nRow = 2 nCol = 1 on 5 nRow = 2 nCol = 2 on 6 nRow = 2 nCol = 3 on 7 nRow = 3 nCol = 1 on 8 nRow = 3 nCol = 2 on 9 nRow = 3 nCol = 3 off exit ok next return [nRow,nCol] func ChangeActivePlayer() if cActivePlayer = :x cActivePlayer = :o else cActivePlayer = :x ok func CheckGameOver aList = [ aGameMap[1][1], aGameMap[1][2], aGameMap[1][3], aGameMap[2][1], aGameMap[2][2], aGameMap[2][3], aGameMap[3][1], aGameMap[3][2], aGameMap[3][3] ] for item in aList switch item on :x item = 1 on :o item = 2 on :n item = 0 off next nStatus = CheckWinner(aList) if nStatus oGameOver { Switch nStatus on 1 Player1Win(this) on 2 Player2Win(this) on 3 NoOneWin(this) off } refreshGame() ok func refreshGame aGameMap = [ [ :n , :n , :n ] , [ :n , :n , :n ] , [ :n , :n , :n ] ] (continues on next page) 59.3. TicTacToe 3D Game 775
815.
Ring Documentation, Release1.16 (continued from previous page) cActivePlayer = :x func CheckWinner lst //vertical check for v=1 to 9 step 3 if lst[v]!=0 and lst[v+1]!=0 and lst[v+2]!=0 if lst[v]=lst[v+1] and lst[v+1]=lst[v+2] return lst[v] ok ok next //horizontal for h=1 to 3 if lst[h]!=0 and lst[h+3]!=0 and lst[h+6]!=0 if lst[h]=lst[h+3] and lst[h+3]=lst[h+6] return lst[h] ok ok next //Cross if lst[1]!=0 and lst[5]!=0 and lst[9]!=0 if lst[1]=lst[5] and lst[5]=lst[9] return lst[1] ok ok if lst[3]!=0 and lst[5]!=0 and lst[7]!=0 if lst[3]=lst[5] and lst[5]=lst[7] return lst[3] ok ok //tie tie=true for i=1 to 9 if lst[i]=0 tie=false exit ok next if tie=true return 3 ok return 0 class GameOver font bitmap func loadresources font = al_load_ttf_font("font/pirulen.ttf",54,0 ) bitmap = al_load_bitmap("image/ballon.png") func destroyResources al_destroy_bitmap(bitmap) al_destroy_font(font) func Player1Win oGame showMsg(oGame,80,430,"Good job X you won!") func Player2Win oGame showMsg(oGame,80,430,"Good job O you won!") func NoOneWin oGame showMsg(oGame,150,430,"Oh no it's a tie!") func ShowMsg oGame,x,y,cMsg (continues on next page) 59.3. TicTacToe 3D Game 776
816.
Ring Documentation, Release1.16 (continued from previous page) oGame { drawScene() al_flip_display() al_rest(0.3) newdisplay = al_create_display(SCREEN_W,SCREEN_H) al_set_window_title(newdisplay,TITLE) al_clear_to_color(al_map_rgb(255,255,255)) al_draw_bitmap(this.bitmap,200,50,1) al_draw_text(this.font, al_map_rgb(0,0,255), x,y, ALLEGRO_ALIGN_LEFT,cMsg) al_flip_display() al_rest(2) al_destroy_display(newdisplay) al_set_target_backbuffer(display) } class GameCube bitmap bitmap2 bitmap3 textureX textureO textureN xrot = 0.0 yrot = 0.0 zrot = 0.0 func loadresources bitmap = al_load_bitmap("image/o.png") textureO = al_get_opengl_texture(bitmap) bitmap2 = al_load_bitmap("image/x.png") textureX = al_get_opengl_texture(bitmap2) bitmap3 = al_load_bitmap("image/empty.png") textureN = al_get_opengl_texture(bitmap3) func destroyResources al_destroy_bitmap(bitmap) al_destroy_bitmap(bitmap2) al_destroy_bitmap(bitmap3) func cube(x,y,z,nTexture) glLoadIdentity() glTranslatef(x,y,z) glRotatef(xrot,1.0,0.0,0.0) glRotatef(yrot,0.0,1.0,0.0) glRotatef(zrot,0.0,0.0,1.0) setCubeTexture(nTexture) drawCube() func setCubeTexture cTexture switch cTexture on :x glBindTexture(GL_TEXTURE_2D, textureX) on :o glBindTexture(GL_TEXTURE_2D, textureO) on :n glBindTexture(GL_TEXTURE_2D, textureN) off (continues on next page) 59.3. TicTacToe 3D Game 777
817.
Ring Documentation, Release1.16 (continued from previous page) func Rotate xrot += 0.3 * 5 yrot += 0.2 * 5 zrot += 0.4 * 5 func drawcube glBegin(GL_QUADS) // Front Face glTexCoord2f(0.0, 0.0) glVertex3f(-1.0, -1.0, 1.0) glTexCoord2f(1.0, 0.0) glVertex3f( 1.0, -1.0, 1.0) glTexCoord2f(1.0, 1.0) glVertex3f( 1.0, 1.0, 1.0) glTexCoord2f(0.0, 1.0) glVertex3f(-1.0, 1.0, 1.0) // Back Face glTexCoord2f(1.0, 0.0) glVertex3f(-1.0, -1.0, -1.0) glTexCoord2f(1.0, 1.0) glVertex3f(-1.0, 1.0, -1.0) glTexCoord2f(0.0, 1.0) glVertex3f( 1.0, 1.0, -1.0) glTexCoord2f(0.0, 0.0) glVertex3f( 1.0, -1.0, -1.0) // Top Face glTexCoord2f(0.0, 1.0) glVertex3f(-1.0, 1.0, -1.0) glTexCoord2f(0.0, 0.0) glVertex3f(-1.0, 1.0, 1.0) glTexCoord2f(1.0, 0.0) glVertex3f( 1.0, 1.0, 1.0) glTexCoord2f(1.0, 1.0) glVertex3f( 1.0, 1.0, -1.0) // Bottom Face glTexCoord2f(1.0, 1.0) glVertex3f(-1.0, -1.0, -1.0) glTexCoord2f(0.0, 1.0) glVertex3f( 1.0, -1.0, -1.0) glTexCoord2f(0.0, 0.0) glVertex3f( 1.0, -1.0, 1.0) glTexCoord2f(1.0, 0.0) glVertex3f(-1.0, -1.0, 1.0) // Right face glTexCoord2f(1.0, 0.0) glVertex3f( 1.0, -1.0, -1.0) glTexCoord2f(1.0, 1.0) glVertex3f( 1.0, 1.0, -1.0) glTexCoord2f(0.0, 1.0) glVertex3f( 1.0, 1.0, 1.0) glTexCoord2f(0.0, 0.0) glVertex3f( 1.0, -1.0, 1.0) // Left Face glTexCoord2f(0.0, 0.0) glVertex3f(-1.0, -1.0, -1.0) glTexCoord2f(1.0, 0.0) glVertex3f(-1.0, -1.0, 1.0) glTexCoord2f(1.0, 1.0) glVertex3f(-1.0, 1.0, 1.0) glTexCoord2f(0.0, 1.0) glVertex3f(-1.0, 1.0, -1.0) glEnd() class GameBackground nBackX = 0 nBackY = 0 nBackDiffx = -1 nBackDiffy = -1 nBackMotion = 1 aBackMotionList = [ [ -1, -1 ] , # Down - Right [ 0 , 1 ] , # Up [ -1, -1 ] , # Down - Right [ 0 , 1 ] , # Up [ 1 , -1 ] , # Down - Left [ 0 , 1 ] , # Up (continues on next page) 59.3. TicTacToe 3D Game 778
818.
Ring Documentation, Release1.16 (continued from previous page) [ 1 , -1 ] , # Down - Left [ 0 , 1 ] # Up ] bitmap func Update draw() motion() func draw al_draw_bitmap(bitmap,nBackX,nBackY,1) func motion nBackX += nBackDiffx nBackY += nBackDiffy if (nBackY = -350) or (nBackY = 0) nBackMotion++ if nBackMotion > len(aBackMotionList) nBackMotion = 1 ok nBackDiffx = aBackMotionList[nBackMotion][1] nBackDiffy = aBackMotionList[nBackMotion][2] ok func loadResources bitmap = al_load_bitmap("image/back.jpg") func destroyResources al_destroy_bitmap(bitmap) class GameSound sample sampleid func loadresources sample = al_load_sample( "sound/music1.wav" ) sampleid = al_new_allegro_sample_id() al_play_sample(sample, 1.0, 0.0,1.0,ALLEGRO_PLAYMODE_LOOP,sampleid) func destroyResources al_destroy_allegro_sample_id(sampleid) al_destroy_sample(sample) class GraphicsAppBase display event_queue ev timeout timer redraw = true FPS = 60 SCREEN_W = 1024 SCREEN_H = 700 KEY_UP = 1 KEY_DOWN = 2 KEY_LEFT = 3 (continues on next page) 59.3. TicTacToe 3D Game 779
819.
Ring Documentation, Release1.16 (continued from previous page) KEY_RIGHT = 4 Key = [false,false,false,false] Mouse_X = 0 Mouse_Y = 0 TITLE = "Graphics Application" PRINT_MOUSE_XY = False func start SetUp() loadResources() eventsLoop() destroy() func setup al_init() al_init_font_addon() al_init_ttf_addon() al_init_image_addon() al_install_audio() al_init_acodec_addon() al_reserve_samples(1) al_set_new_display_flags(ALLEGRO_OPENGL) display = al_create_display(SCREEN_W,SCREEN_H) al_set_window_title(display,TITLE) al_clear_to_color(al_map_rgb(0,0,0)) event_queue = al_create_event_queue() al_register_event_source(event_queue, al_get_display_event_source(display)) ev = al_new_allegro_event() timeout = al_new_allegro_timeout() al_init_timeout(timeout, 0.06) timer = al_create_timer(1.0 / FPS) al_register_event_source(event_queue, al_get_timer_event_source(timer)) al_start_timer(timer) al_install_mouse() al_register_event_source(event_queue, al_get_mouse_event_source()) al_install_keyboard() al_register_event_source(event_queue, al_get_keyboard_event_source()) func eventsLoop while true al_init_timeout(timeout, 0.06) al_wait_for_event_until(event_queue, ev, timeout) switch al_get_allegro_event_type(ev) on ALLEGRO_EVENT_DISPLAY_CLOSE CloseEvent() on ALLEGRO_EVENT_TIMER redraw = true on ALLEGRO_EVENT_MOUSE_AXES mouse_x = al_get_allegro_event_mouse_x(ev) mouse_y = al_get_allegro_event_mouse_y(ev) if PRINT_MOUSE_XY see "x = " + mouse_x + nl see "y = " + mouse_y + nl (continues on next page) 59.3. TicTacToe 3D Game 780
820.
Ring Documentation, Release1.16 (continued from previous page) ok on ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY mouse_x = al_get_allegro_event_mouse_x(ev) mouse_y = al_get_allegro_event_mouse_y(ev) on ALLEGRO_EVENT_MOUSE_BUTTON_UP MouseClickEvent() on ALLEGRO_EVENT_KEY_DOWN switch al_get_allegro_event_keyboard_keycode(ev) on ALLEGRO_KEY_UP key[KEY_UP] = true on ALLEGRO_KEY_DOWN key[KEY_DOWN] = true on ALLEGRO_KEY_LEFT key[KEY_LEFT] = true on ALLEGRO_KEY_RIGHT key[KEY_RIGHT] = true off on ALLEGRO_EVENT_KEY_UP switch al_get_allegro_event_keyboard_keycode(ev) on ALLEGRO_KEY_UP key[KEY_UP] = false on ALLEGRO_KEY_DOWN key[KEY_DOWN] = false on ALLEGRO_KEY_LEFT key[KEY_LEFT] = false on ALLEGRO_KEY_RIGHT key[KEY_RIGHT] = false on ALLEGRO_KEY_ESCAPE exit off off if redraw and al_is_event_queue_empty(event_queue) redraw = false drawScene() al_flip_display() ok callgc() end func destroy destroyResources() al_destroy_timer(timer) al_destroy_allegro_event(ev) al_destroy_allegro_timeout(timeout) al_destroy_event_queue(event_queue) al_destroy_display(display) al_exit() func loadresources func drawScene func destroyResources func MouseClickEvent exit # Exit from the Events Loop (continues on next page) 59.3. TicTacToe 3D Game 781
821.
Ring Documentation, Release1.16 (continued from previous page) func CloseEvent exit # Exit from the Events Loop Screen Shot: 59.4 More 3D Samples You will find the samples in ring/samples/3D folder The next screen shot for the Top-Down view - Many levels of cubes sample 59.4. More 3D Samples 782
822.
Ring Documentation, Release1.16 The next screen shot for the Camera Sample The next screen shot for the Camera and background sample Developer : Azzeddine Remmal 59.4. More 3D Samples 783
CHAPTER SIXTY THE GOLD MAGIC800 GAME In this chapter we will learn about the Gold Magic 800 Game The game is developed using Ring, RingAllegro and RingOpenGL You will find the game in ring/applications/goldmagic800 folder 60.1 The Game Story Your friend discovered a unique and special box, created by the best wizard in the world 7000 years ago, when you close this box and move it; you will find a new gold under the box, it’s an infinite source of gold. The Box exists in a special environment full of puzzles, no one can enter this environment because it’s protected by the magic. Your friend created a new robot using nanotechnology that can move the box using a remote control device. Your mission is to solve all of these puzzles and get this box forever to be the richest people in the world. 60.2 How to play? The Gold Magic 800 is a puzzle game that will teach your unconscious mind to think like an entrepreneur. The game is based on moving your box around to get gold score (=800) to open the First Door (Box Number 1) Then directly put your box on the Door (this will open the next door), Then continue to put your box on all of the next doors in the level, You need the score (800) only for the first door, The next doors doesn’t require this condition, but your way of gold will be converted to a wall once you put the Box on any door, so select your path carefully. 60.3 What will you learn? 1- Plan First 2- Move to your target directly then go to get the required resources 3- Look to the future when you evaluate the different solutions 4- Try to avoid mistakes, Also learn from them 5- Respect the Cost (800) 6- Focus and be careful 7- Be patient and Enjoy! 785
825.
Ring Documentation, Release1.16 60.4 Screen Shots We can select the level The next screen shot for level (1) The Gold Magic 800 Level Editor 60.4. Screen Shots 786
826.
Ring Documentation, Release1.16 60.5 Source Code You will find the Level Editor source code in this folder https://github.com/ring-lang/ring/tree/master/applications/goldmagic800/editor The user interface of the Level Editor is designed using the Ring Form Designer. 60.5. Source Code 787
827.
Ring Documentation, Release1.16 The next file contains the Level Editor Controller Class https://github.com/ring-lang/ring/blob/master/applications/goldmagic800/editor/editorController.ring You will find the Game Engine source code in this folder https://github.com/ring-lang/ring/tree/master/applications/goldmagic800 60.5. Source Code 788
828.
CHAPTER SIXTYONE RINGTILENGINE EXTENSION In thischapter we will learn about using the RingTilengine extension. This extension provides complete support for Tilengine The 2D retro graphics engine with raster effects Tilengine URL: https://github.com/megamarc/Tilengine Useful links (Original documentation for C programmers) • Getting started: https://github.com/ring-lang/Tilengine/blob/master/docs/quick_guide.md • Initialization: https://github.com/ring-lang/Tilengine/blob/master/docs/starting.md • Using the window: https://github.com/ring-lang/Tilengine/blob/master/docs/windowing.md • External rendering: https://github.com/ring-lang/Tilengine/blob/master/docs/rendering.md • Background layers: https://github.com/ring-lang/Tilengine/blob/master/docs/layers.md • Sprites: https://github.com/ring-lang/Tilengine/blob/master/docs/sprites.md Useful tools • Tiled Map Editor: https://www.mapeditor.org/ • aseprite: https://www.aseprite.org/ • Piskel: https://www.piskelapp.com/ • GrafX2: http://grafx2.chez.com/ Support • Tilengine Forum: http://www.tilengine.org/forum/ 61.1 Getting Started Example (1): load "tilengine.ring" TLN_Init(400, 240, 1, 0, 0) TLN_SetLoadPath("assetssonic") foreground = TLN_LoadTilemap ("Sonic_md_fg1.tmx", NULL) TLN_SetLayerTilemap(0, foreground) TLN_CreateWindow(NULL, 0) (continues on next page) 789
829.
Ring Documentation, Release1.16 (continued from previous page) while TLN_ProcessWindow() TLN_DrawFrame(0) end TLN_DeleteTilemap(foreground) TLN_Deinit() Screen Shot: 61.2 More Samples Example (2): load "tilengine.ring" WIDTH = 400 HEIGHT = 240 frame = 0 /* setup engine */ TLN_Init(WIDTH, HEIGHT, 1,0,0) /* load layer */ tilemap = TLN_LoadTilemap("assets/sonic/Sonic_md_fg1.tmx", NULL) /* setup the layer */ TLN_SetLayer(0, NULL, tilemap) (continues on next page) 61.2. More Samples 790
830.
Ring Documentation, Release1.16 (continued from previous page) TLN_SetBGColor(32,32,128) /* main loop */ TLN_CreateWindow(NULL, 0) while TLN_ProcessWindow () /* scroll the layer, one pixel per frame */ TLN_SetLayerPosition (0, frame, 0) /* render to the window */ TLN_DrawFrame (0) frame++ end /* release resources */ TLN_DeleteTilemap(tilemap) TLN_Deinit() Screen Shot: Example (3): load "tilengine.ring" /* engine init */ TLN_Init(640,480,0,0,1) /* load resources */ TLN_SetLoadPath("assets/color") (continues on next page) 61.2. More Samples 791
831.
Ring Documentation, Release1.16 (continued from previous page) background = TLN_LoadBitmap("beach.png") palette = TLN_GetBitmapPalette(background) sp = TLN_LoadSequencePack("beach.sqx") sequence = TLN_FindSequence(sp, "beach") /* setup */ TLN_SetBGBitmap(background) TLN_SetPaletteAnimation(0, palette, sequence, true) /* main loop */ TLN_CreateWindow(NULL, 0) TLN_DisableCRTEffect() while(TLN_ProcessWindow()) TLN_DrawFrame(0) end TLN_DeleteBitmap(background) TLN_DeleteSequencePack(sp) TLN_Deinit() Screen Shot: Example (4): load "tilengine.ring" WIDTH = 400 HEIGHT= 240 LAYER_FOREGROUND = 0 LAYER_BACKGROUND = 1 MAX_LAYER = 2 (continues on next page) 61.2. More Samples 792
Ring Documentation, Release1.16 (continued from previous page) /* startup display */ TLN_CreateWindow (NULL, 0) x = int2fix(-136) y = int2fix(336) s = 0 a = float2fix(0.2) angle = 0 BuildSinTable () /* main loop */ while (TLN_ProcessWindow ()) TLN_SetLayerTilemap (LAYER_FOREGROUND, horizon) TLN_SetLayerTilemap (LAYER_BACKGROUND, horizon) TLN_SetLayerPosition (LAYER_FOREGROUND, lerp(angle*2, 0,360, ˓ →0,256), 24) TLN_SetLayerPosition (LAYER_BACKGROUND, lerp(angle, 0,360, 0, ˓ →256), 0) TLN_ResetLayerMode (LAYER_BACKGROUND) /* input */ if (TLN_GetInput (INPUT_LEFT)) angle-=2 elseif (TLN_GetInput (INPUT_RIGHT)) angle+=2 ok if (TLN_GetInput (INPUT_UP)) s += a if (s > int2fix(2)) s = int2fix(2) ok elseif (s >= a) s -= a ok if (TLN_GetInput (INPUT_DOWN)) s -= a if (s < -int2fix(2)) s = -int2fix(2) ok elseif (s <= -a) s += a ok if (s != 0) angle = angle%360 if (angle < 0) angle += 360 ok x += CalcSin (angle, s) y -= CalcCos (angle, s) ok (continues on next page) 61.2. More Samples 797
837.
Ring Documentation, Release1.16 (continued from previous page) /* render to window */ TLN_DrawFrame (0) end /* deinit */ TLN_DeleteTilemap (road) TLN_DeleteTilemap (horizon) TLN_DeleteWindow () TLN_Deinit () /* raster callback (virtual HBLANK) */ func raster_callback line = TLN_GETSCANLINE() if (line = 24) TLN_SetLayerTilemap (LAYER_BACKGROUND, road) TLN_SetLayerPosition (LAYER_BACKGROUND, fix2int(x), fix2int(y)) TLN_DisableLayer (LAYER_FOREGROUND) elseif (line >= 24) s0 = float2fix (0.2) s1 = float2fix (5.0) s = lerp (line, 24,HEIGHT, s0,s1) scale = fix2float (s) TLN_SetLayerTransform (LAYER_BACKGROUND, angle, WIDTH/2, HEIGHT, ˓ →scale, scale) ok func lerp x,x0,x1,fx0,fx1 return (fx0) + ((fx1) - (fx0)) * ((x) - (x0))/((x1) - (x0)) func float2fix f return f * (1 << FIXED_BITS) func int2fix i return i << FIXED_BITS func fix2int f return f >> FIXED_BITS func fix2float f return f/(1 << FIXED_BITS) Screen Shot: 61.2. More Samples 798
Ring Documentation, Release1.16 (continued from previous page) speed = 1.0f ok elseif speed > 0.0 speed -= 0.02 if speed < 0.0 speed = 0.0f ok ok if TLN_GetInput (INPUT_LEFT) speed -= 0.02 if speed < -1 speed = -1 ok elseif speed < 0 speed += 0.02 if speed > 0 speed = 0 ok ok /* scroll */ pos_foreground += 3*speed TLN_SetLayerPosition (LAYER_FOREGROUND, pos_foreground, ypos) for c=1 to 6 pos_background[c] += (inc_background[c] * speed) next /* render to window */ TLN_DrawFrame (0) end /* deinit */ TLN_DeleteTilemap (foreground) TLN_DeleteTilemap (background) TLN_DeleteSequencePack (sp) TLN_Deinit () /* raster callback (virtual HBLANK) */ func raster_callback line = TLN_GetScanLine() pos =- 1 if line=0 pos = pos_background[1] elseif line=32 pos = pos_background[2] elseif line=48 pos = pos_background[3] elseif line=64 pos = pos_background[4] elseif line=112 pos = pos_background[5] elseif line >= 152 pos = lerp (line, 152,224, pos_background[5], pos_background[6]) ok (continues on next page) 61.2. More Samples 808
848.
Ring Documentation, Release1.16 (continued from previous page) if pos != -1 TLN_SetLayerPosition (LAYER_BACKGROUND, pos, 0) ok /* background color gradients */ if line < 112 InterpolateColor (line, 0,112, sky[1], sky[2], color) TLN_SetBGColor (color[1], color[2], color[3]) elseif line >= 144 InterpolateColor (line, 144,HEIGHT, sky[3], sky[4], color) TLN_SetBGColor (color[1], color[2], color[3]) ok func InterpolateColor v,v1,v2,color1,color2,result result[1] = lerp (v, v1,v2, color1[1], color2[1]) result[2] = lerp (v, v1,v2, color1[2], color2[2]) result[3] = lerp (v, v1,v2, color1[3], color2[3]) /* linear interpolation */ func lerp x,x0,x1,fx0,fx1 return (fx0) + ((fx1) - (fx0))*((x) - (x0))/((x1) - (x0)) Screen Shot: 61.2. More Samples 809
849.
Ring Documentation, Release1.16 61.3 Using LibSDL and Tilengine Example (11): load "tilengine.ring" load "libsdl.ring" width = 640 height = 480 func main # Start Tilengine TLN_Init(width, height, 2, 80, 0) # Start LibSDL SDL_Init(SDL_INIT_EVERYTHING) win = SDL_CreateWindow("Using LibSDL and Tilengine", 100, 100, width, ˓ →height, SDL_WINDOW_SHOWN|SDL_WINDOW_OPENGL) ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_ ˓ →RENDERER_PRESENTVSYNC ) # Create the Surface in LibSDL that will be used by Tilengine for Drawing surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0,0) # Get the Surface Pixels pointer from the Surface Structure pixels = SDL_Get_SDL_Surface_Pixels(surface) # Pass the Pixels pointer to Tilengine TLN_SetRenderTarget(pixels, width * 4) # Using Tilengine TLN_SetLoadPath("assetssonic") foreground = TLN_LoadTilemap ("Sonic_md_fg1.tmx", NULL) TLN_SetLayerTilemap(0, foreground) # Using LibSDL Events Loop oEvent = SDL_New_SDL_Event() while true # Using Tilengine to Update the Frame TLN_UpdateFrame(0) # Draw Tilengine results using LibSDL # ( Surface --> Texture --> Render) tex = SDL_CreateTextureFromSurface(ren, surface); SDL_RenderCopy2(ren,tex) SDL_DestroyTexture(tex) # Draw Rectangle using LibSDL rect = SDL_New_SDL_Rect() SDL_Set_SDL_Rect_x(rect,10) SDL_Set_SDL_Rect_y(rect,10) SDL_Set_SDL_Rect_w(rect,100) SDL_Set_SDL_Rect_h(rect,100) SDL_SetRenderDrawColor(ren,255,255,255,255) SDL_RenderDrawRect(ren,rect) SDL_Destroy_SDL_Rect(rect) (continues on next page) 61.3. Using LibSDL and Tilengine 810
850.
Ring Documentation, Release1.16 (continued from previous page) # Display Results using LibSDL SDL_RenderPresent(ren) # Check Events SDL_PollEvent(oEvent) switch SDL_Get_SDL_Event_Type(oEvent) on SDL_Get_SDL_Quit() exit on SDL_Get_SDL_Keydown() Key = SDL_Get_ ˓ →SDL_Event_key_Keysym_Sym(oEvent) if key = 27 ˓ →exit ok off end # End of Tilengine Usage TLN_Deinit() # End of LibSDL Usage SDL_DestroyWindow(win) SDL_Quit() Screen Shot: 61.3. Using LibSDL and Tilengine 811
851.
Ring Documentation, Release1.16 Example (12): load "tilengine.ring" load "libsdl.ring" factor = 3 width = 400*factor height = 220*factor func main # Start Tilengine TLN_Init(width, height, 2, 80, 0) # Start LibSDL SDL_Init(SDL_INIT_EVERYTHING) win = SDL_CreateWindow("Using LibSDL and Tilengine", 40, 40, width, ˓ →height, SDL_WINDOW_SHOWN|SDL_WINDOW_OPENGL) ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_ ˓ →RENDERER_PRESENTVSYNC ) # Create the Surface in LibSDL that will be used by Tilengine for Drawing surface = SDL_CreateRGBSurface(0, width, height, 32, 0,0,0,0) # Get the Surface Pixels pointer from the Surface Structure (continues on next page) 61.3. Using LibSDL and Tilengine 812
852.
Ring Documentation, Release1.16 (continued from previous page) pixels = SDL_Get_SDL_Surface_Pixels(surface) # Pass the Pixels pointer to Tilengine TLN_SetRenderTarget(pixels, width * 4) # Using Tilengine TLN_SetLoadPath("assetssonic") foreground = TLN_LoadTilemap ("Sonic_md_fg1.tmx", NULL) TLN_SetLayerTilemap(0, foreground) # Using LibSDL Events Loop oEvent = SDL_New_SDL_Event() while true # Using Tilengine to Update the Frame TLN_UpdateFrame(0) # Draw Tilengine results using LibSDL # ( Surface --> Texture --> Render) tex = SDL_CreateTextureFromSurface(ren, surface); rectSource = SDL_New_SDL_Rect() SDL_Set_SDL_Rect_x(rectSource,0) SDL_Set_SDL_Rect_y(rectSource,0) SDL_Set_SDL_Rect_w(rectSource,400) SDL_Set_SDL_Rect_h(rectSource,220) rectDest = SDL_New_SDL_Rect() SDL_Set_SDL_Rect_x(rectDest,0) SDL_Set_SDL_Rect_y(rectDest,0) SDL_Set_SDL_Rect_w(rectDest,width) SDL_Set_SDL_Rect_h(rectDest,height) SDL_RenderCopy(ren,tex,rectSource,rectDest) SDL_Destroy_SDL_Rect(rectSource) SDL_Destroy_SDL_Rect(rectDest) SDL_DestroyTexture(tex) # Draw Rectangle using LibSDL rect = SDL_New_SDL_Rect() SDL_Set_SDL_Rect_x(rect,40) SDL_Set_SDL_Rect_y(rect,5) SDL_Set_SDL_Rect_w(rect,230) SDL_Set_SDL_Rect_h(rect,200) SDL_SetRenderDrawColor(ren,255,255,255,255) SDL_RenderDrawRect(ren,rect) SDL_Destroy_SDL_Rect(rect) # Display Results using LibSDL SDL_RenderPresent(ren) # Check Events SDL_PollEvent(oEvent) switch SDL_Get_SDL_Event_Type(oEvent) on SDL_Get_SDL_Quit() exit (continues on next page) 61.3. Using LibSDL and Tilengine 813
853.
Ring Documentation, Release1.16 (continued from previous page) on SDL_Get_SDL_Keydown() Key = SDL_Get_ ˓ →SDL_Event_key_Keysym_Sym(oEvent) if key = 27 ˓ →exit ok off end # End of Tilengine Usage TLN_Deinit() # End of LibSDL Usage SDL_DestroyWindow(win) SDL_Quit() Screen Shot: 61.4 Reference Constants: • TILENGINE_VER_MAJ • TILENGINE_VER_MIN • TILENGINE_VER_REV • TILENGINE_HEADER_VERSION • FLAG_NONE • FLAG_FLIPX 61.4. Reference 814
CHAPTER SIXTYTWO PERFORMANCE TIPS In thischapter we will learn more about the Ring performance. 62.1 Introduction Ring is designed to be a simple, small and flexible language in the first place, but also it is fast enough for many applications. Ring can do each of the next tasks in around 1 second using normal computers in the market during the last 5 years (1) Compiling 100,000 lines of code (2) Executing empty loop that count from 1 to 10,000,000 (3) Executing 1000 search operation using linear search in a list contains 100,000 items, trying to find the last item (The worst case) (4) Creating list contains 1,000,000 items then summing all of the list items (5) Adding 20,000 items to the ListWidget in GUI applications (6) Adding 5,000 nodes to the TreeWidget in GUI applications (7) Printing 10,000 messages to the terminal in Console applications Also when we need more speed we can use C/C++ extensions! Example: ? "Create list contains 100,000 items" aList = 1:100000 ? "Do 1000 search operation - Find the last item (Worst Case!)" c = clock() for t = 1 to 1000 find(alist,100000) next ? "Time: " + ( clock() - c ) / clockspersecond() + " seconds" Output: Create list contains 100,000 items Do 1000 search operation - Find the last item (Worst Case!) Time: 0.87 seconds 823
863.
Ring Documentation, Release1.16 Example: load "guilib.ring" func main new qApp { win = new qWidget() { move(100,100) resize(500,500) setWindowTitle("Many Tree Items - Testing Performance") tree = new qTreeWidget(win) { blocksignals(True) setUpdatesEnabled(False) root = new qTreeWidgetItem() root.setText(0,"The Root Node") t1 = clock() for t = 1 to 5000 oItem = new qTreeWidgetItem() oItem.settext(0,"Item " + t) root.addchild(oItem) next cTime = (clock()-t1)/clockspersecond() setHeaderLabel("Creating 5000 nodes in " + cTime + " seconds. ˓ →") addTopLevelItem(root) expanditem(root) blocksignals(False) setUpdatesEnabled(True) } oLayout = new qVBoxLayout() { addWidget(tree) } setLayout(oLayout) show() } exec() } Output: 62.1. Introduction 824
864.
Ring Documentation, Release1.16 62.2 Creating Lists Example: ? "Create the list using the Range operator" t1 = clock() aList = 1:1000000 ? "Time : " + ((clock()-t1)/clockspersecond()) + " seconds" ? "Create the list using the For loop" t1 = clock() aList = [] for x = 1 to 1000000 aList + x next ? "Time : " + ((clock()-t1)/clockspersecond()) + " seconds" ? "Create the list using the list() function and the For loop" t1 = clock() aList = list(1000000) for x = 1 to 1000000 aList[x] = x next ? "Time : " + ((clock()-t1)/clockspersecond()) + " seconds" Output: 62.2. Creating Lists 825
865.
Ring Documentation, Release1.16 Create the list using the Range operator Time : 0.48 seconds Create the list using the For loop Time : 0.79 seconds Create the list using the list() function and the For loop Time : 1.56 seconds Note: Creating lists using the Range operator is faster than using the For loop or the list() function 62.3 Arithmetic Operations Example: ? "Using * operator" t1 = clock() for x = 1 to 1000000 out = x * 2 next ? "Time : " + ((clock()-t1)/clockspersecond()) + " seconds" ? "Using *= operator" t1 = clock() for x = 1 to 1000000 out = x out *= 2 next ? "Time : " + ((clock()-t1)/clockspersecond()) + " seconds" Output: Using * operator Time : 1.34 seconds Using *= operator Time : 0.47 seconds Note: Using the *= operator is faster that using the * operator 62.4 Using len() and For Loops Example: aList = 1:1000000 ? "Using len() in the For loop" t1 = clock() for x = 1 to len(aList) next ? "Time : " + ((clock()-t1)/clockspersecond()) + " seconds" (continues on next page) 62.3. Arithmetic Operations 826
866.
Ring Documentation, Release1.16 (continued from previous page) ? "Using len() before the For loop" t1 = clock() nMax = len(aList) for x = 1 to nMax next ? "Time : " + ((clock()-t1)/clockspersecond()) + " seconds" Output: Using len() in the For loop Time : 5.50 seconds Using len() before the For loop Time : 0.24 seconds Note: Using len() before the For loop is faster than using len() in the For loop. 62.5 Calling Functions and Methods Example: ? "calling 100000 functions" t1 = clock() for x = 1 to 100000 test() next ? "Time : " + ((clock()-t1)/clockspersecond()) + " seconds" o1 = new test ? "calling 100000 methods using the dot operator" t1 = clock() for x = 1 to 100000 o1.test() next ? "Time : " + ((clock()-t1)/clockspersecond()) + " seconds" ? "calling 100000 methods using braces " t1 = clock() for x = 1 to 100000 o1 { test() } next ? "Time : " + ((clock()-t1)/clockspersecond()) + " seconds" func test class test func test Output: 62.5. Calling Functions and Methods 827
867.
Ring Documentation, Release1.16 calling 100000 functions Time : 0.28 seconds calling 100000 methods using the dot operator Time : 0.36 seconds calling 100000 methods using braces Time : 1.19 seconds Note: Calling functions is faster than calling methods but the difference is very small. Note: Using the dot operator to call methods is faster than using braces. 62.5. Calling Functions and Methods 828
868.
CHAPTER SIXTYTHREE COMMAND LINE OPTIONS Thering language takes source code file (.ring) or the object file (.ringo) as input to execute, also the language provide other options like Option Description -tokens Print a list of tokens in the source code file -rules Print grammar rules applied on the tokens -ic Print the intermediate byte code (before execution) -icfinal Print the final byte code (after execution) -cgi Print http response header before error messages -norun Don’t run the program after compiling -ins Print instruction operation code before execution -performance Print clock before and after program execution -go Generate Object File -geo Generate embedded object file (C source code) -w Display Warnings 63.1 Printing Tokens Example: Func Main See "Hello World" + nl for x = 1 to 10 see x + nl next test() func test see "welcome" + nl o1 = new point { x=10 y=20 z=30 } see o1 class point x y z Command: ring test.ring -tokens -norun Output: 829
869.
Ring Documentation, Release1.16 =================================================== Tokens - Generated by the Scanner =================================================== Keyword : FUNC Identifier : main EndLine Keyword : SEE Literal : Hello World Operator : + Identifier : nl EndLine Keyword : FOR Identifier : x Operator : = Number : 1 Keyword : TO Number : 10 EndLine Keyword : SEE Identifier : x Operator : + Identifier : nl EndLine Keyword : NEXT EndLine Identifier : test Operator : ( Operator : ) EndLine Keyword : FUNC Identifier : test EndLine Keyword : SEE Literal : welcome Operator : + Identifier : nl EndLine Identifier : o1 Operator : = Keyword : NEW Identifier : point Operator : { Identifier : x Operator : = Number : 10 Identifier : y Operator : = Number : 20 Identifier : z Operator : = Number : 30 Operator : } EndLine Keyword : SEE Identifier : o1 EndLine (continues on next page) 63.1. Printing Tokens 830
870.
Ring Documentation, Release1.16 (continued from previous page) Keyword : CLASS Identifier : point Identifier : x Identifier : y Identifier : z EndLine =================================================== 63.2 Printing Rules Command: ring test.ring -rules -norun Output: =================================================== Grammar Rules Used by The Parser =================================================== Rule : Program --> {Statement} Line 1 Rule : Statement --> 'Func' Identifier [ParaList] Line 2 Rule : Factor --> Literal Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus] Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : Arithmetic --> Arithmetic + Arithmetic Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> 'See' Expr Line 3 Rule : Factor --> Number Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR (continues on next page) 63.2. Printing Rules 831
Ring Documentation, Release1.16 63.6 No Run Command: ring test.ring -norun 63.7 Printing Instruction Operation Code Command: ring test.ring -ins Output: =================================================== Operation : ReturnNull PC : 1 Line Number : 1 , File test.ring SP (After) : 0 - FuncSP : 0 LineNumber 1 =================================================== ..... ..... ..... Tip: Output removed from the previous example because it’s very large! 63.8 Performance Command: ring test.ring -performance Output: =================================================== Date : 2015/09/15 Time : 15:56:17 Clock : 0 =================================================== Hello World 1 2 3 4 5 6 7 8 (continues on next page) 63.6. No Run 843
883.
Ring Documentation, Release1.16 (continued from previous page) 9 10 welcome x: 10.000000 y: 20.000000 z: 30.000000 =================================================== Date : 2015/09/15 Time : 15:56:17 Clock : 0 =================================================== 63.9 Generate Object File You can generate object file (.ringo) from your source code file (.ring) using -go option Tip: You will get one object file to use for distributing/running your application which may contains one or many ring source files that you can keep or distribute based on the application (commercial or open source). Command: ring test.ring -go To run the compiled object file ring test.ringo 63.10 Generate Embedded Object File You can generate embedded object file (C source code) from your source code file (*.ring) using -geo option Command: ring test.ring -geo This command will generate at least three files test.c ringappcode.c ringappcode.h More files could be generated based on the project size The generated files will pass the byte code to Ring VM to be executed 63.9. Generate Object File 844
884.
CHAPTER SIXTYFOUR DISTRIBUTING RING APPLICATIONS(MANUAL) In this chapter we will learn about distributing Ring applications. The next method is old and was used in Ring 1.5 and previous versions! Starting from Ring 1.6 we have a nice tool called Ring2EXE Using Ring2EXE we can distribute applications quickly for Windows, Linux and macOS Check the Ring2EXE chapter for more information! 64.1 Distributing Applications for Microsoft Windows Step 1: Copy c:ringbin folder to be for example c:myapp Step 2: Rename c:myappring.exe to c:myappmyapp.exe Step 3: Create a file c:myappring.ring And write Load "myapp.ring" When you run myapp.exe the file ring.ring will be executed automatically So your file myapp.ring will be called and executed Or just rename myapp.ring to ring.ring It’s a fast way to distribute applications. 845
885.
Ring Documentation, Release1.16 64.2 Protecting the Source Code Step 1: Execute the next command ring myapp.ring -go This will generate one object file (myapp.ringo) from the project files (*.ring) Step 2: Rename myapp.ringo to ring.ringo When you run the executable file (ring.exe) or (myapp.exe) the file ring.ringo will be executed. 64.3 The files ring.ring and ring.ringo Ring will run ring.ring or ring.ringo only when (1) The file exist in the current directory (2) No file is passed to (ring.exe) to execute We added the support to ring.ring (and ring.ringo) for a way to distribute Ring apps (before Ring2EXE) 64.4 Creating Windows Installer There are many tools that you can use to distribute your application. Check : nullsoft scriptable install system URL : http://nsis.sourceforge.net/Main_Page 64.5 Using C/C++ Compiler and Linker Another method to distribute applications is to use a C/C++ compiler. Ring can be embedded in C/C++ projects, We can create executable files using a C/C++ compiler by embedding the Ring language in our project. Check the “Embedding Ring Language in C/C++ Programs” chapter. Using this way we will avoid using ring.ring or ring.ringo files. 64.2. Protecting the Source Code 846
886.
Ring Documentation, Release1.16 64.6 Distributing Applications and Games for Mobile Ring can be embedded in a Qt projects or LibSDL projects to build Mobile applications and Games. You can build the Qt project or the LibSDL project and get the Android package directly (*.apk) Check Ring distributions for Mobile development using Qt or LibSDL. 64.6. Distributing Applications and Games for Mobile 847
887.
CHAPTER SIXTYFIVE DISTRIBUTING RING APPLICATIONSUSING RING2EXE In this chapter we will learn about distributing Ring applications. Starting from Ring 1.6 we have a nice tool called Ring2EXE (Written in Ring itself) Using Ring2EXE we can distribute applications quickly for Windows, Linux, macOS, WebAssembly and Mobile devices Note: We can use the Distribute Menu in the Ring Notepad application (More Easy) 65.1 Using Ring2EXE ring2exe filename.ring [Options] This will set filename.ring as input to the program The next files will be generated filename.ringo (The Ring Object File - by Ring Compiler) filename.c (The C Source code file Contains the ringo file content Will be generated by this program) filename_buildvc.bat (Will be executed to build filename.c using Visual C/C++) filename_buildgcc.bat (Will be executed to build filename.c using GNU C/C++) filename_buildclang.bat (Will be executed to build filename.c using CLang C/C++) filename.obj (Will be generated by the Visual C/C++ compiler) filename.exe (Will be generated by the Visual C/C++ Linker) filename (Executable File - On Linux & MacOS X platforms) 65.2 How Ring2EXE works? At first the Ring compiler will be used to generate the Ring object file (*.ringo) If we have a C compiler (optional), This object file will be embedded inside a C source code file Then using the C compiler and the Ring library (Contains the Ring Virtual Machine) the executable file will be generated! If we don’t have a C compiler, the Ring executable will be copied and renamed to your application name And your Ring object file (*.ringo) will become ring.ringo to be executed at startup of the executable file. 848
888.
Ring Documentation, Release1.16 So it’s better and easy to have a C compiler on your machine to be used by Ring2EXE. 65.3 Example We have test.ring contains the next code see "Hello, World!" + nl To build the executable file for Windows, Linux or macOS ring2exe test.ring To run the program (Windows) test To run the program (Linux and macOS) ./test 65.4 Options -keep : Don't delete Temp. Files -static : Build Standalone Executable File (Don't use ring.dll/ring.so/ring.dylib) -gui : Build GUI Application (Hide the Console Window) -dist : Prepare application for distribution -allruntime : Include all libraries in distribution -mobileqt : Prepare Qt Project to distribute Ring Application for Mobile -webassemblyqt : Prepare Qt Project to distribute Ring Application for the web ˓ →(WebAssembly) -noqt : Remove RingQt from distribution -noallegro : Remove RingAllegro from distribution -noopenssl : Remove RingOpenSSL from distribution -nolibcurl : Remove RingLibCurl from distribution -nomysql : Remove RingMySQL from distribution -noodbc : Remove RingODBC from distribution -nosqlite : Remove RingSQLite from distribution -noopengl : Remove RingOpenGL from distribution -nofreeglut : Remove RingFreeGLUT from distribution -nolibzip : Remove RingLibZip from distribution -noconsolecolors : Remove RingConsoleColors from distribution -nomurmuhash : Remove RingMurmurHash from distribution -nocruntime : Remove C Runtime from distribution -qt : Add RingQt to distribution -allegro : Add RingAllegro to distribution -openssl : Add RingOpenSSL to distribution -libcurl : Add RingLibCurl to distribution -mysql : Add RingMySQL to distribution -odbc : Add RingODBC to distribution -sqlite : Add RingSQLite to distribution -postgresql : Add RingPostgreSQL to distribution -opengl : Add RingOpenGL to distribution (continues on next page) 65.3. Example 849
889.
Ring Documentation, Release1.16 (continued from previous page) -freeglut : Add RingFreeGLUT to distribution -libzip : Add RingLibZip to distribution -libuv : Add RingLibuv to distribution -consolecolors : Add RingConsoleColors to distribution -murmurhash : Add RingMurmurHash to distribution -cruntime : Add C Runtime to distribution 65.5 Building standalone console application Using the “-static” option we can build executable console application So we don’t have to use ring.dll, ring.so or ring.dylib This avoid only the need to Ring dynamic link library If you are using another libraries, You will need to include it with your application. ring2exe test.ring -static 65.6 Distributing RingAllegro Applications We have test2.ring contains the next code # Just a simple program to test Ring2EXE Tool! # Using RingAllegro load "gameengine.ring" # Give Control to the Game Engine func main # Called by the Game Engine oGame = New Game # Create the Game Object { title = "My First Game" } To build the executable file and prepare for distributing the Game We use “-dist” option and “-allruntime” to include all libraries ring2exe test2.ring -dist -allruntime After executing the previous command On Windows we will have : target/windows folder On Linux we will have : target/linux folder On macOS we will have : target/macos folder The previous command will add all of the Ring runtime libraries to our distribution But we may need only RingAllegro, So it’s better to use the next command ring2exe test2.ring -dist -allegro -cruntime 65.5. Building standalone console application 850
890.
Ring Documentation, Release1.16 This will produce smaller size distribution and will avoid the runtime files that we don’t need! Also we could use the “-gui” option to hide the console window So it’s better to use the next command ring2exe test2.ring -dist -gui -allegro -cruntime 65.7 Distributing RingQt Applications We have test3.ring contains the next code # Just a simple program to test Ring2EXE Tool! # Using RingQt load "guilib.ring" new qApp { new qWidget() { setwindowtitle("Hello, World!") resize(400,400) show() } exec() } To build the executable file and prepare for distributing the GUI application We use “-dist” option and “-allruntime” to include all libraries ring2exe test3.ring -dist -allruntime After executing the previous command On Windows we will have : target/windows folder On Linux we will have : target/linux folder On macOS we will have : target/macos folder The previous command will add all of the Ring runtime libraries to our distribution But we may need only RingQt, So it’s better to use the next command ring2exe test3.ring -dist -qt -cruntime This will produce smaller size distribution and will avoid the runtime files that we don’t need! Also we could use the “-gui” option to hide the console window So it’s better to use the next command ring2exe test3.ring -dist -gui -qt -cruntime 65.7. Distributing RingQt Applications 851
891.
Ring Documentation, Release1.16 65.8 Distributing Applications for Mobile using RingQt To prepare a Qt project for your RingQt application (test3.ring) use the “-mobileqt” option Example : ring2exe test3.ring -dist -mobileqt After executing the previous command, We will have the Qt project in target/mobile/qtproject folder The main project file will be project.pro which we can open using the Qt Creator IDE. Also we will have the resource file : project.qrc Another important file is our C++ main file : main.cpp 65.9 Distributing Applications for WebAssembly using RingQt To prepare a Qt project (WebAssembly) for your RingQt application (myapp.ring) use the “-webassemblyqt” option Example : ring2exe myapp.ring -dist -webassemblyqt After executing the previous command, We will have the Qt project in target/webassembly/qtproject folder The main project file will be project.pro which we can open using the Qt Creator IDE. Also we will have the resource file : project.qrc Another important file is our C++ main file : main.cpp 65.10 Building the Cards Game for Mobile using RingQt For a better example, consider building an Android package for the Cards game that comes with the Ring language in this folder : ring/application/cards The Cards game folder contains three files cards.ring : The Game source code cards.jpg : The image file used by the game project.qrc : Resource file to be used with the Qt project The resource file contains the next content <RCC> <qresource> <file>cards.ringo</file> <file>cards.jpg</file> </qresource> </RCC> We have two files in the resource file The first file is cards.ringo (The Ring Object File) and the second file is cards.jpg (The image file) 65.8. Distributing Applications for Mobile using RingQt 852
892.
Ring Documentation, Release1.16 As a start, Ring2EXE will generate this resource file in target/mobile/qtproject/project.qrc But this file will contains only cards.ringo (That Ring2EXE will generate by calling Ring compiler) We need to update this resource file to add the image file : cards.jpg After this update, we copy the resource file to the main application folder So when we use Ring2EXE again, Our updated resource file will be used! Now to build the cards game for Mobile (1) Run the next command ring2exe cards.ring -dist -mobileqt (2) Open target/mobile/qtproject/project.pro using Qt creator (3) Build and Run using Qt Creator How the Cards game will find the image file ? RingQt comes with a simple function : AppFile() that we can use to determine the files that we may access on Desktop or Mobile platforms The next code from cards.ring mypic = new QPixmap(AppFile("cards.jpg")) So all what you need is using AppFile() function around your image files! 65.11 Building the Weight History Application for Mobile using RingQt Another example to distribute your application for Mobile Devices using Ring2EXE and Qt consider building an Android package for the Weight History application that comes with the Ring language in this folder : ring/application/weighthistory The Weight History application folder contains four files weighthistory.ring : The application source code weighthistory.db : The SQLite database project.qrc : The resource file for the Qt project main.cpp : The main C++ source file for the Qt project To build the Weight History application for Mobile (1) Run the next command ring2exe weighthistory.ring -dist -mobileqt (2) Open target/mobile/qtproject/project.pro using Qt creator (3) Build and Run using Qt Creator The resource file (project.qrc) contains two files 65.11. Building the Weight History Application for Mobile using RingQt 853
893.
Ring Documentation, Release1.16 <RCC> <qresource> <file>weighthistory.ringo</file> <file>weighthistory.db</file> </qresource> </RCC> The first file is weighthistory.ringo (Ring Object File - Generated by Ring2EXE by calling Ring compiler) The database file : weighthistory.db The main.cpp contains the next little update, To copy the database file from resources to a writable location on the mobile device QString path3 ; path3 = path+"/weighthistory.db"; QFile::copy(":/weighthistory.db",path3); You will need to do this with database files only! When we use Ring2EXE, the tool will check for project.qrc and main.cpp, if they exist then your updated files will be used in target/mobile/qtproject instead of the default version generated by Ring2EXE So Use Ring2EXE to generate these files, Then copy them to your application folder when you update them. 65.12 Building the Form Designer for Mobile using RingQt To build the Form Designer application (ring/tools/formdesigner) for Mobile (1) Run the next command ring2exe formdesigner.ring -dist -mobileqt (2) Open target/mobile/qtproject/project.pro using Qt creator (3) Build and Run using Qt Creator in the folder ring/application/formdesigner You will find the resource file : project.qrc It will be used automatically by Ring2EXE <RCC> <qresource> <file>formdesigner.ringo</file> <file>image/allevents.png</file> <file>image/checkbox.png</file> <file>image/close.png</file> <file>image/combobox.bmp</file> <file>image/datepicker.bmp</file> <file>image/dial.png</file> <file>image/formdesigner.png</file> <file>image/frame.png</file> <file>image/grid.bmp</file> <file>image/hyperlink.png</file> <file>image/image.png</file> <file>image/label.png</file> <file>image/layout.png</file> (continues on next page) 65.12. Building the Form Designer for Mobile using RingQt 854
894.
Ring Documentation, Release1.16 (continued from previous page) <file>image/lcdnumber.png</file> <file>image/listview.png</file> <file>image/lock.png</file> <file>image/new.png</file> <file>image/open.png</file> <file>image/progressbar.png</file> <file>image/project.png</file> <file>image/pushbutton.png</file> <file>image/radiobutton.png</file> <file>image/save.png</file> <file>image/saveas.png</file> <file>image/select.png</file> <file>image/slider.png</file> <file>image/spinner.bmp</file> <file>image/statusbar.png</file> <file>image/tab.png</file> <file>image/textarea.png</file> <file>image/textfield.png</file> <file>image/timer.png</file> <file>image/toolbar.png</file> <file>image/tree.bmp</file> <file>image/videowidget.png</file> <file>image/webview.png</file> </qresource> </RCC> As we did in the Cards game, The Form Designer will use the AppFile() function to determine the name of the Image files. The next code from ring/tools/formdesigner/mainwindow/formdesignerview.ring func CreateToolBar aBtns = [ new qtoolbutton(win) { setbtnimage(self,AppFile("image/new.png")) setclickevent(Method(:NewAction)) settooltip("New File") } , new qtoolbutton(win) { setbtnimage(self,AppFile("image/open.png")) setclickevent(Method(:OpenAction)) settooltip("Open File") } , new qtoolbutton(win) { setbtnimage(self,AppFile("image/save.png")) setclickevent(Method(:SaveAction)) settooltip("Save") } , new qtoolbutton(win) { setbtnimage(self,AppFile("image/saveas.png")) setclickevent(Method(:SaveAsAction)) settooltip("Save As") } , new qtoolbutton(win) { setbtnimage(self,AppFile("image/close.png")) setclickevent(Method(:ExitAction)) settooltip("Exit") (continues on next page) 65.12. Building the Form Designer for Mobile using RingQt 855
895.
Ring Documentation, Release1.16 (continued from previous page) } ] tool1 = win.addtoolbar("files") { for x in aBtns { addwidget(x) addseparator() } } From this example, We know that we can use sub folders for images. 65.13 Creating the Qt resource file using Folder2qrc When we have large RingQt project that contains a lot of images and files, We need to add these files to the resource file ( *.qrc ) when distributing applications for Mobile devices. Instead of adding these files one by one, Ring 1.6 comes with a simple tool that save our time, It’s called Folder2qrc. Example: folder2qrc formdesigner.ring We determine the main source file while we are in the application folder, and Folder2qrc will check all of the files in the current folder and sub folders, Then add them to the resource file after the mainfile.ringo (In our example this will be formdesigner.ringo) The output file will be : project.qrc You can open it and remove the files that you don’t need in the resources! 65.14 Important Information about Ring2EXE • Using Ring2EXE to prepare distribution will delete all of the files in the old distribution for example, if you have target/windows folder then used ring2exe test3.ring -dist -allruntime The files in target/windows will be deleted before adding the files again This is important when you prepare a distribution for Mobile devices ring2exe test3.ring -dist -mobileqt If you modified the resource file : project.qrc or the main file : main.cpp Don’t forget to copy them to the application folder! So Ring2EXE can use the updated version if you tried the previous command again! • Ring2EXE is written in Ring, and you can read the source code from https://github.com/ring-lang/ring/blob/master/tools/ring2exe/ring2exe.ring • The libraries information are stored in a separated files, So these files can be updated in the future automatically to support new libraries https://github.com/ring-lang/ring/blob/master/tools/ring2exe/libs 65.13. Creating the Qt resource file using Folder2qrc 856
896.
CHAPTER SIXTYSIX THE RING PACKAGEMANAGER (RINGPM) In this chapter we will learn about using the Ring Package Manager (RingPM) RingPM is a tool for discovering, installing and updating Ring packages. 66.1 Features The Package Manager uses Semantic Versioning to check compatibility between packages The Package Manager comes with the next options Usage : ringpm [command] Command : search [keywords...] Command : refresh : Update the Registry (Packages List) Command : install [ <packagename> [from <UserName>] [branch <branchname>] ] Command : list [-u : check updates] Command : run [packagename] Command : update <packagename> Command : remove <packagename> Command : format : Delete All Packages Command : new <packagename> Command : package : Create package in the current folder 66.2 Discovering Packages We can discover new packages using the Search command Using this command we can search in the RingPM Registry (Packages Index) The RingPM Registry is a local copy of all registered packages. ringpm search [keywords...] Example: ringpm search notepad Output: Package : ringnotepad (Ring Notepad) Package : notepadppeditorextension (Notepad++ Editor Extension package) 857
897.
Ring Documentation, Release1.16 To print all packages in the RingPM Registry, use the search command without keywords. Example: ringpm search 66.3 Updating the RingPM Registry The RingPM Registry is a local copy of all registered packages. We can update the local copy using the Refresh command Example: ringpm refresh Output: No updates to the Registry, Nothing to do! Or The Registry is updated from revision 110 (2019/01/13) to revision 112 (2019/01/15) 66.4 Installing Packages We can install new packages using the Install command ringpm install [ <packagename> [from <UserName>] [branch <branchname>] ] We can type only the package name to get the package information from the RingPM Registry or we can determine the user name (GitHub) and the branch name of the github project (optional). If the current folder is a package folder then we don’t need to write the package name. Example (1) : ringpm install ringnotepad Example (2) : ringpm install goldmagic800 Example (3) : ringpm install gameoflife If the package is not added to the RingPM Registry, We can install it directly from the GitHub user Example (4) : ringpm install firstpackage from mahmoudfayed To run the package after installation 66.3. Updating the RingPM Registry 858
898.
Ring Documentation, Release1.16 ringpm run firstpackage To install a package in the current folder Example (5) : ringpm install 66.5 Printing List of Installed Packages We can know the installed packages using the List command ringpm list [-u : check updates] Example ringpm list Output (analogclock) : The AnalogClock Package [master] -- (1.0.0) (androidringlibsdl) : The AndroidRingLibSDL Package [master] -- (1.0.0) (androidringqt) : The AndroidRingQt Package [master] -- (1.0.0) (atomeditorextension) : The AtomEditorExtension Package [master] -- (1.0.0) (bignumber) : The BigNumber Package [master] -- (1.0.0) (calculator) : The Calculator Package [master] -- (1.0.0) (cards) : The Cards Package [master] -- (1.0.0) (checkers) : The Checkers Package [master] -- (1.0.0) (chess) : The Chess Package [master] -- (1.0.0) .... To check for new updates ringpm list -u 66.6 Run Package After installing a package, we can run it using the Run command. ringpm run [packagename] Example(1): ringpm run ringnotepad Example(2): ringpm run goldmagic800 Example(3): ringpm run gameoflife 66.5. Printing List of Installed Packages 859
899.
Ring Documentation, Release1.16 To run a package in the current folder Example(4): ringpm run 66.7 Update Package We can update a package using the Update command ringpm update <packagename> Example: ringpm update ringnotepad 66.8 Remove Package We can remove a package using the Remove command ringpm remove <packagename> Example: ringpm remove ringnotepad 66.9 Deleting All Packages We can delete all packages using the Format command Example: ringpm format 66.10 Creating New Package We can create new package using the New command ringpm new <packagename> Example: ringpm new myapp This will create new folder called my myapp The new folder will contains the next file • package.ring : The package description and files 66.7. Update Package 860
900.
Ring Documentation, Release1.16 • main.ring : main program (used by the Run command) • lib.ring : library file for the package File : main.ring # The Main File load "lib.ring" func main ? "Hello, World!" File : lib.ring # The Library File File : package.ring aPackageInfo = [ :name = "The myapp Package", :description = "Our myapp package using the Ring programming language", :folder = "myapp", :developer = "", :email = "", :license = "MIT License", :version = "1.0.0", :ringversion = "1.10", :versions = [ [ :version = "1.0.0", :branch = "master" ] ], :libs = [ [ :name = "", :version = "", :providerusername = "" ] ], :files = [ "lib.ring", "main.ring" ], :ringfolderfiles = [ ], :windowsfiles = [ ], :linuxfiles = [ ], :ubuntufiles = [ ], :fedorafiles = [ (continues on next page) 66.10. Creating New Package 861
901.
Ring Documentation, Release1.16 (continued from previous page) ], :macosfiles = [ ], :windowsringfolderfiles = [ ], :linuxringfolderfiles = [ ], :ubunturingfolderfiles = [ ], :fedoraringfolderfiles = [ ], :macosringfolderfiles = [ ], :run = "ring main.ring", :windowsrun = "", :linuxrun = "", :macosrun = "", :ubunturun = "", :fedorarun = "", :setup = "", :windowssetup = "", :linuxsetup = "", :macossetup = "", :ubuntusetup = "", :fedorasetup = "", :remove = "", :windowsremove = "", :linuxremove = "", :macosremove = "", :ubunturemove = "", :fedoraremove = "" ] 66.11 The Package Description File The package description file contains the package information defined in the list aPackageInfo Attribute Description Name Package Name Description Package Description Folder The Folder Name (Will be created in ring/ringpm/packages) Developer The Package Developer Name Email The Package Developer Email License The Package License Version The Current Version of the Package (Latest Release) continues on next page 66.11. The Package Description File 862
902.
Ring Documentation, Release1.16 Table 1 – continued from previous page Attribute Description RingVersion The Required Ring Language Version (Minimum Version) Versions List of different versions provided by different branches in the GitHub project Libs List of dependencies (Defined by name, version & GitHub user name) Files List of files (will be installed in ring/ringpm/packages/[Folder] RingFolderFiles List of files (will be installed in ring folder) WindowsFiles Like (Files) but for Microsoft Windows Only LinuxFiles Like (Files) but for Linux Only MacOSFiles Like (Files) but for macOS Only UbuntuFiles Like (Files) but for Ubuntu Only FedoraFiles Like (Files) but for Fedora Only WindowsRingFolderFiles Like (RingFolderFiles) but for Microsoft Windows Only LinuxRingFolderFiles Like (RingFolderFiles) but for Linux Only MacOSRingFolderFiles Like (RingFolderFiles) but for macOS Only UbuntuRingFolderFiles Like (RingFolderFiles) but for Ubuntu Only FedoraRingFolderFiles Like (RingFolderFiles) but for Fedora Only Run System Command (Command prompt or Terminal) to run the package WindowsRun Like (Run) but for Microsoft Windows Only LinuxRun Like (Run) but for Linux Only MacOSRun Like (Run) but for macOS Only UbuntuRun Like (Run) but for Ubuntu Only FedoraRun Like (Run) but for Fedora Only Setup System Command (Command prompt or Terminal) after downloading the package files WindowsSetup Like (Setup) but for Microsoft Windows Only LinuxSetup Like (Setup) but for Linux Only MacOSSetup Like (Setup) but for macOS Only UbuntuSetup Like (Setup) but for Ubuntu Only FedoraSetup Like (Setup) but for Fedora Only Remove System Command (Command prompt or Terminal) before removing the package files WindowsRemove Like (Remove) but for Microsoft Windows Only LinuxRemove Like (Remove) but for Linux Only MacOSRemove Like (Remove) but for macOS Only UbuntuRemove Like (Remove) but for Ubuntu Only FedoraRemove Like (Remove) but for Fedora Only 66.12 Create Package in the Current Folder To create a package for an application that already exists, go to the application folder then type ringpm package This will create the package definition file (package.ring) and will add all of the application files to the package definition. Each RingPM package contains the package definition file (package.ring) The package definition file is a list that describe the package information and files. Example : The package definition file for the Ring Notepad package 66.12. Create Package in the Current Folder 863
Ring Documentation, Release1.16 66.13 The RingPM Registry File The RingPM Registry is a local copy of all registered packages. aPackagesRegistry = [ [ :name = "ringpresentation", :description = "Powerpoint presentation for the Ring programming language", :ProviderUserName = "ringpackages" ] # ... ] Each package is defined using a list that determine • Package Name • Package Description • Provider User Name (GitHub User Name) We can register new packages by updating the registry file then sending a Pull Request URL : https://github.com/ring-lang/ring/blob/master/tools/ringpm/registry/registry.ring 66.13. The RingPM Registry File 866
906.
CHAPTER SIXTYSEVEN USING ZEROLIB In thischapter we will learn how to use the ZeroLib library. 67.1 Introduction ZeroLib is a simple library written in Ring. The library provide classes for Lists and String where the index starts from 0. 67.2 Z() function Syntax: Z(String|List) ---> New Object (ZeroBasedString|ZeroBasedList) 67.3 ZeroBasedList Class Simple class provide a List where the index starts from zero. Methods: Method Description/Output Init(List) Add(Value) Add item to the list Insert(nIndex,Value) Inset Item after nIndex Find(Value) Find item Delete(nIndex) Delete item from the list Item(nIndex) Get item from the list First() Get the first item in the list Last() Get the last item in the list Set(nIndex,Value) Set item value FindInColumn(nCol,Value) Find item in a column Sort() Sort items - return new list Reverse() Reverse items - return new list Swap(nIndex1,nIndex2) Swap two items Example: 867
907.
Ring Documentation, Release1.16 load "zerolib.ring" ? "Using List - Index start from 0" List = Z( [1,2,3] ) List.Add(4) List.Add(5) ? List[0] ? List[1] ? List[2] ? List[3] ? List[4] nIndex = List.find(2) ? "Find(2) = " + nIndex List.delete(0) ? "After deleting the first item : List[0]" ? "Now List[0] = " + List[0] Output: Using List - Index start from 0 1 2 3 4 5 Find(2) = 1 After deleting the first item : List[0] Now List[0] = 2 67.4 ZeroBasedString Class Simple class provide a String where the index starts from zero. Method Description/Output Init(String|Number) Lower() New String - Lower case characters Upper() New String - Upper case characters Left(x) New String - contains x characters from the left Right(x) New String - contains x characters from the right Lines() Number - Lines count Trim() New String - Remove Spaces Copy(x) New String - repeat string x times strcmp(cString) Compare string with cString tolist() List (String Lines to String Items) tofile(cFileName) Write string to file mid(nPos1,nPos2) New String - from nPos1 to nPos2 getfrom(nPos1) New String - from nPos1 to the end of the string replace(cStr1,cStr2,lCase) New String - Replace cStr1 with cStr2 , lCase (True=Match Case) split() List - Each Word as list item startswith(substring) Return true if the start starts with a substring endswith(substring) Return true if the start ends with a substring Example: 67.4. ZeroBasedString Class 868
908.
Ring Documentation, Release1.16 load "zerolib.ring" ? "Using String - Index start from 0" String = Z( "Welcome" ) ? String[0] ? String[1] ? String[2] ? String[3] ? String[4] ? String[5] ? String[6] Output: Using String - Index start from 0 W e l c o m e 67.5 Source Code We can find the library source code in this folder URL : https://github.com/ring-lang/ring/tree/master/libraries/zerolib 67.5. Source Code 869
909.
CHAPTER SIXTYEIGHT FOXRING FUNCTIONS REFERENCE Aclass contains functions similar to FoxPro functions. 68.1 FoxRing functions Function Name Description frAbs() Returns the absolute value of the specified numeric expression. frAddBs() Adds a backslash (if needed) to a path expression. frALines() Creates an Array with the content of the specified string. frAllTrim() Removes all leading and trailing spaces of the specified string. frAsc() Returns the ANSI value for the leftmost character in a character expression. frAt() Searches a character expression for the occurrence of another character expression. frAtC() Searches a character expression for the occurrence of another character expression without regard for the case of these two expressions. frBetween() Determines whether the value of an expression is inclusively between the values of two expressions of the same type. frChr() Returns the character associated with the specified numeric ANSI code. frEmpty() Determines whether an expression evaluates to empty. frFile() Checks if a file exists on disk. frFileToStr() Returns the contents of a file as a character string. frForceExt() Returns a string with the old file name extension replaced by a new extension. frForcePath() Returns a file name with a new path name substituted for the old one. frIif() Returns one of two values depending on the value of a logical expression. frInList() Determines whether an expression matches another expression in a list. frInt() Evaluates a numeric expression and returns the integer portion of the expression. frJustDrive() Returns the drive letter from a complete path. frJustExt() Returns the characters of a file extension from a complete path. frJustFName() Returns the file name portion of a complete path and file name. frJustPath() Returns the path portion of a complete path and file name. frJustStem() Returns the stem name (the file name before the extension) from a complete path and file name. frLen() Determines the number of characters in a character expression, indicating the length of the expression. frListToString() Creates a string with the string elements of an Array. frLTrim() Removes all leading spaces or parsing characters from the specified character expression. frPadL() Returns a string from an expression, padded with spaces or characters to a continues on next page 870
910.
Ring Documentation, Release1.16 Table 1 – continued from previous page Function Name Description specified length on the left side. frPadR() Returns a string from an expression, padded with spaces or characters to a specified length on the right side. frProper() Returns from a character expression a string capitalized as appropriate for proper names. frReplicate() Returns a character string that contains a specified character expression repeated a specified number of times. frRTrim() Removes all trailing spaces or parsing characters from the specified character expression. frSetIfEmpty() Set a Value into a variable if the variable value is empty, null or zero. frSetSeparatorTo() Specifies the character for the numeric place separator. frSpace() Returns a character string composed of a specified number of spaces. frStr() Returns the character equivalent of a numeric expression. frStringToList() Creates a List with the content of the specified string. frStrTran() Searches a character expression for a second character expression and replaces each occurrence with a third character expression. frStuff() Returns a new character string replaced by a specified number of characters in a character expression with another character expression. frSubStr() Returns a character string from the given character expression, starting at a specified position in the character expression and continuing for a specified number of characters. frTransform() Returns a character string from an expression in a format determined by a format code. frVal() Returns a numeric value from a character expression composed of numbers. frVarType() Returns the data type of an expression. 68.2 frAbs() function * Syntax : lnReturnValue = frAbs(tnExpression) * Description : Returns the absolute value of the specified numeric expression. * : * Arguments : <tnExpression> * : Specifies the numeric expression whose absolute value frAbs() * : returns. * Returns : <lnReturnValue> * : Returns the absolute value of the specified numeric expression. 68.3 frAsc() function * Syntax : lnReturnValue = frAsc(tcExpression) * Description : Returns the ANSI value for the leftmost character in * : a character expression. * Arguments : <tcExpression> * : Specifies the character expression containing the character * : whose ANSI value frAsc() * : returns. Any characters after the first character in * : tcExpression are ignored by frAsc(). (continues on next page) 68.2. frAbs() function 871
911.
Ring Documentation, Release1.16 (continued from previous page) * Returns : <lnReturnValue> * : returns the position of the character in the character * : table of the current code page. * : Every character has a unique ANSI value in the * : range from 0 to 255. 68.4 frAddBs() function * Syntax : lcReturnValue = frAddBs(tcPath) * Description : Adds a backslash (if needed) to a path expression. * : * Arguments : <tcPath> * : Specifies the path name to which to add the backslash. * : * Returns : <lcReturnValue> The path with the backslash. 68.5 frAt() function * Syntax : lnPos = frAt(tcToSearch, tcString, tnOccurrence) * Description : Searches a character expression for the occurrence of * : another character expression. * : The search performed by frAt() is case-sensitive. * : * Arguments : <tcToSearch> * : Specifies the character expression to search * : for in <tcString>. * : <tcString> * : Specifies the character expression to search * : for <tcToSearch>. * : <tnOccurrence> * : Specifies which occurrence, first, second, third, * : and so on, of <tcToSearch> to search for * : in <tcString>. * : By default, frAt() searches for the first occurrence * : of <tcToSearch> (tnOccurrence = 1). * Returns : Numeric. frAt() returns an integer indicating the * : position of the first character for a * : character expression or memo field within another * : character expression or memo field, * : beginning from the leftmost character. If the * : expression or field is not found, or if * : <tnOccurrence> is greater than the number of * : times <tcToSearch> occurs in <tcString>, frAt() * : returns 0. 68.4. frAddBs() function 872
912.
Ring Documentation, Release1.16 68.6 frAtC() function * Syntax : lnPos = frAtC(tcToSearch, tcString, tnOccurrence) * Description : Searches a character expression for the occurrence * : of another character expression * : without regard for the case of these two expressions. * : * Arguments : <tcToSearch> * : Specifies the character expression to search * : for in <tcString>. * : <tcString> * : Specifies the character expression to search * : for <tcToSearch>. * : <tnOccurrence> * : Specifies which occurrence, first, second, third, * : and so on, of <tcToSearch> to search for * : in tcString. * : By default, frAtC() searches for the first occurrence * : of <tcToSearch> (tnOccurrence = 1). * Returns : Numeric. frAtC() returns an integer indicating the * : position of the first character for a * : character expression or memo field within * : another character expression or memo field, * : beginning from the leftmost character. If the * : expression or field is not found, or if * : <tnOccurrence> is greater than the number of * : times <tcToSearch> occurs in <tcString>, frAtC() * : returns 0. 68.7 frChr() function * Syntax : lcReturnValue = frChr(tnExpression) * Description : Returns the character associated with the specified numeric * : ANSI code. * Arguments : <tnExpression> * : Specifies a number between 0 and 255 whose equivalent ANSI * : character frChr() returns. * Returns : <lcReturnValue> * : Returns a single character corresponding to the numeric * : position of the character in the * : character table of the current code page. * : * Remarks : tnExpression must be between 0 and 255 68.6. frAtC() function 873
913.
Ring Documentation, Release1.16 68.8 frEmpty() function * Syntax : llReturnValue = frEmpty(tuExpression) * Description : Determines whether an expression evaluates to empty. * : * Arguments : <tuExpression> * : Specifies the expression that EMPTY() evaluates. * : You can specify an expression with Character, * : Numeric, or logical type. * : * Returns : <llReturnValue> Logical 68.9 frFile() function * Syntax : llReturnValue = frFile(tcFileName, tnFlag) * Description : Checks if the specified file exists on disk. * : * Arguments : <tcFileName> * : Specifies the name of the file to check. * : tcFileName must include * : the file extension. You can include a path with * : the file name to * : search for a file in a directory or on a drive * : other than the current directory or drive. * : * : <tnFlag> * : tnFlag was included for future compatibility. * : In this version, It always returns true whenever * : the file exists on disk. * Returns : <llReturnValue> Logical * : True if file exists on disk. * : False if file doesn't exist on disk. 68.10 frFileToStr() function * Syntax : lcReturnValue = frFileToStr(tcFileName) * Description : Returns the contents of a file as a character string. * : * Arguments : <tcFileName> * : Specifies the name of the file whose contents are * : returned as a character * : string. If the file is in a directory other than * : the current default directory, * : include a path with the file name. * : * Returns : <lcReturnValue> * : A character string with the content of the specified file. * : 68.8. frEmpty() function 874
914.
Ring Documentation, Release1.16 68.11 frStr() function * Syntax : lcReturnValue = frStr(tnValue, tnLen, tnDec) * Description : Returns the character equivalent of a numeric expression. * : * Arguments : <tnValue> * : Specifies the numeric expression to evaluate. * : * : <tnLen> * : Specifies the length of the character string returned. * : If tnLen is 0, tnLen defaults to 10 characters. * : If tnLen < 0 returns one string with same length as the number. * : Note * : If the expression contains a decimal point, * : the length includes one character for * : the decimal point and one character * : for each digit in the character string. * : * : <tnDec> * : Specifies the number of decimal places in the * : character string returned. * : To specify the number of decimal places using * : tnDec, you must include nLength. If nDecimalPlaces is omitted, * : the number of decimal places defaults to zero (0). * : * Returns : Character data type. frStr() returns a character string * : equivalent to the specified numeric expression. * : Depending on certain conditions, frStr() can return the following: * : If you specify fewer decimal places than exist in tnValue, * : the return value is rounded up. To round results to the nearest * : decimal place instead of upward, include the ROUND( ) function. * : For more information, see ROUND( ) Function. * : If nExpression is an integer, and nLength is less than * : the number of digits in nExpression, frStr( ) returns a string of * : asterisks, indicating numeric overflow. * : If nExpression contains a decimal point, and nLength is equal * : to or less than the number of digits to the left of the decimal * : point, frStr( ) returns a string of asterisks, * : indicating numeric overflow. * : If nLength is greater than the length of the value evaluated * : by nExpression, frStr( ) returns a character string padded with * : leading spaces. * : If nExpression has Numeric or Float type, and nLength * : is less than the number of digits in nExpression, and , frStr( ) * : returns a value using scientific notation. 68.11. frStr() function 875
915.
Ring Documentation, Release1.16 68.12 frSetIfEmpty() function * Syntax : tuReturnValue = frSetIfEmpty(tuValue, tuNewValue) * Description : Set a Value into a variable if the variable * : value is empty, null or zero. * Arguments : <tuValue> * : The value to evaluate. * : * : <tuNewValue> * : The value to set if tuValue is empty. * : * Returns : tuNewValue if tuValue is empty, otherwise * : returns the original value. * Remarks : This function doesn't exist in VFP. 68.13 frSpace() function * Syntax : lcReturnValue = frSpace(tnSpaces) * Description : Returns a character string composed of a * : specified number of spaces. * Arguments : <tnSpaces> * : Specifies the number of spaces that frSpace() returns. * : * Returns : <lcReturnValue> * : Character 68.14 frInList() function * Syntax : llReturnValue = frInList(tuExpression, taList) * Description : Determines whether an expression matches another * : expression in a set of expressions. * Arguments : <tuExpression> * : Specifies the expression frInList() searches for in the List. * : * : <taList> * : Specifies the List of expressions to search. *