Ring Documentation Release 1.10 Ring Team January 25, 2019
CONTENTS 1 Applications developed in little hours 1 1.1 Quotes about Ring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.2 FetchStockData Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.3 Fifteen Puzzle Game 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 1.4 Google API Shortener Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.5 Analog Clock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.6 TicTacToe Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.7 Squares Puzzle Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 1.8 Video-Music-Player Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.9 Calculator Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 1.10 Windows StartUp Manager Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 1.11 Werdy Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 1.12 Samples in this book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 1.13 Innovative . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 1.14 Practical . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 2 Introduction 24 2.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 2.2 Ring and other languages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.3 Special Thanks to Matz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.4 History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 2.5 Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 2.6 License . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 3 Language Design 31 3.1 Why Ring? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 3.2 Designed for a Clear Goal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 3.3 Simple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 3.4 Trying to be natural . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 3.5 Encourage Organization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 3.6 Compact Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 3.7 Define Natural Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 3.8 Define Declarative Languages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 3.9 Syntax Flexibility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 3.10 Transparent Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 3.11 Visual Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 3.12 Smart Garbage Collector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 3.13 No Global Interpreter (VM) Lock - No GIL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 3.14 Fast Enough For Many Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 4 What is new in Ring 1.10? 41 i
4.1 List of changes and new features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 4.2 Chess Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 4.3 Minesweeper Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 4.4 Knight Tour Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 4.5 Game of Life Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 4.6 Pong Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 4.7 Snakes And Ladder Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 4.8 More Games . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 4.9 Ring Extension for Visual Studio Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 4.10 The Ring Package Manager (RingPM) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 4.11 Better Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 4.12 More Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 5 What is new in Ring 1.9? 51 5.1 List of changes and new features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 5.2 New Game : Gold Magic 800 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 5.3 More Games . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 5.4 Better Ring Notepad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 5.5 Better StdLib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 5.6 BigNumber Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 5.7 RingPostgreSQL Extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 5.8 Deploying Web applications in the Cloud . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 5.9 Better RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 5.10 Better Memory Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 5.11 Better Code Generator for Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 5.12 More Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 6 What is new in Ring 1.8? 68 6.1 List of changes and new features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 6.2 Better Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 6.3 Find in files Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 6.4 String2Constant Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 6.5 StopWatch Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 6.6 More 3D Samples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 6.7 Compiling on Manjaro Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 6.8 Using This in the class region as Self . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 6.9 Default value for object attributes is NULL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 6.10 The For Loops uses the local scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 6.11 Merge binary characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 6.12 FoxRing Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 6.13 Better Form Designer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 6.14 Better Cards Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 6.15 Better RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 6.16 Better Code Generator For Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 6.17 Better Ring Compiler and VM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 6.18 Notes to extensions creators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 7 What is new in Ring 1.7? 81 7.1 List of changes and new features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 7.2 New Command: Load Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 7.3 ringvm_see() and ringvm_give() functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 7.4 ring_state_new() and ring_state_mainfile() functions . . . . . . . . . . . . . . . . . . . . . . . . . . 83 7.5 Better Trace Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 7.6 Better Ring Notepad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 ii
7.7 Better RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 7.8 Better Ring2EXE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 7.9 Better RingZip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 7.10 Better Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 7.11 Better Ring VM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 7.12 RingLibuv Extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 8 What is new in Ring 1.6? 89 8.1 List of changes and new features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 8.2 Employee Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 8.3 New Tool: Ring2EXE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 8.4 Better Ring For Android . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 8.5 New Tool: Folder2qrc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 8.6 Better Scripts for building Ring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 8.7 RingConsoleColors Extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 8.8 RingMurmurHash Extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 8.9 Better Ring Notepad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 8.10 Better RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 8.11 Better StdLib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 8.12 Better RingVM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 8.13 Better RingREPL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 8.14 Using Tab instead of char(9) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 8.15 Using CR as Carriage return . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 8.16 Using the ! operator as not . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 8.17 Using && and || operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 8.18 Using ? to print expression then new line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 9 What is new in Ring 1.5? 100 9.1 List of changes and new features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 9.2 Video-Music-Player Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 9.3 Windows StartUp Manager Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 9.4 Calculator Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 9.5 Better Ring Notepad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 9.6 Better StdLib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 9.7 Better WebLib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 9.8 Better RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 9.9 Better Objects Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 9.10 RingFreeGLUT Extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 9.11 RingOpenGL Extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 9.12 Better Code Generator for Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 9.13 Better Documentation Generator for Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 9.14 Ring VM - Tracing Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 9.15 Trace Library and Interactive Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 9.16 More Syntax Flexibility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 9.17 Type Hints Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 9.18 Better Quality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 9.19 What is new in Ring 1.5.1? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 9.20 What is new in Ring 1.5.2? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 9.21 What is new in Ring 1.5.3? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 9.22 What is new in Ring 1.5.4? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142 10 What is new in Ring 1.4? 144 10.1 List of changes and new features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 10.2 Change: Basic Extensions are separated from RingVM . . . . . . . . . . . . . . . . . . . . . . . . . 144 iii
10.3 The Natural Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 10.4 New Style is added to Ring Notepad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 10.5 RingREPL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 10.6 Convert between Numbers and Bytes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 10.7 Better StdLib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 10.8 Better WebLib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 10.9 Better RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 10.10 Qt Class Convertor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 10.11 What is new in Ring 1.4.1? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152 11 What is new in Ring 1.3? 156 11.1 List of changes and new features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 11.2 Better RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 11.3 Better Ring Notepad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160 11.4 Ring mode for Emacs Editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 11.5 Better StdLib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 11.6 Better Loop|Exit Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 11.7 New Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 11.8 Return Self by Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 11.9 Using ‘<’ and ‘:’ operators as ‘from’ keyword . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166 11.10 Embedding Ring in Ring without sharing the State . . . . . . . . . . . . . . . . . . . . . . . . . . . 166 11.11 RingZip Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 11.12 Form Designer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 12 What is new in Ring 1.2? 169 12.1 List of changes and new features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 12.2 New Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 12.3 Better Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170 12.4 Better Ring Notepad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170 12.5 Better RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 12.6 Objects Library for RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 12.7 RingLibCurl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172 12.8 Better Call Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 12.9 Using NULL instead of NULLPointer() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 12.10 Display Warnings Option . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 12.11 Better Quality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 13 What is new in Ring 1.1? 175 13.1 List of changes and new features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 13.2 Better Natural Language Programming Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 13.3 Generate/Execute Ring Object Files (*.ringo) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 13.4 Syntax Flexibility and different styles for I/O and Control Structures . . . . . . . . . . . . . . . . . . 176 13.5 New Functions and Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178 13.6 StdLib functions and classes written in Ring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 13.7 RingLibSDL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 13.8 Demo Project - Game Engine for 2D Games . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 13.9 RingSQLite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 13.10 Better Code Generator for Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183 13.11 Using Self.Attribute in the Class Region to define new attributes . . . . . . . . . . . . . . . . . . . . 183 13.12 Using This.Attribute in nested Braces inside the Class Methods . . . . . . . . . . . . . . . . . . . . 183 13.13 Better Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184 14 Building From Source Code 185 14.1 Building using Microsoft Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 14.2 Building using Ubuntu Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 iv
14.3 Building using Fedora Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 14.4 Building using MacOS X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 14.5 Building using CMake . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 15 How to contribute? 195 15.1 Special thanks to contributors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 15.2 Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 15.3 Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 15.4 Samples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 15.5 Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 15.6 Editors Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 15.7 Libraries in Ring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 15.8 Extensions in C/C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 15.9 Compiler and Virtual Machine (VM) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 15.10 Ideas and suggestions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 16 Getting Started - First Style 197 16.1 Hello World . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 16.2 Run the program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 16.3 Create Executable File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 16.4 Not Case-Sensitive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 16.5 Multi-Line literals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 16.6 Getting Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 16.7 No Explicit End For Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 16.8 Using ? to print expression then new line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 16.9 Writing Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199 17 Getting Started - Second Style 200 17.1 Hello World . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 17.2 Run the program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 17.3 Create Executable File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 17.4 Not Case-Sensitive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 17.5 Multi-Line literals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 17.6 Getting Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 17.7 No Explicit End For Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 17.8 Writing Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 18 Getting Started - Third Style 202 18.1 Hello World . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 18.2 Run the program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 18.3 Create Executable File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 18.4 Not Case-Sensitive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 18.5 Multi-Line literals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 18.6 Getting Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 18.7 No Explicit End For Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 18.8 Writing Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 19 Using Ring Notepad 205 19.1 Ring Notepad - Main Window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 19.2 Creating and running your first Console Application . . . . . . . . . . . . . . . . . . . . . . . . . . 206 19.3 Creating and running your first GUI/Mobile Application . . . . . . . . . . . . . . . . . . . . . . . . 208 19.4 Creating and running your first Web Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209 19.5 Creating and running your first Desktop/Mobile Game . . . . . . . . . . . . . . . . . . . . . . . . . 210 19.6 The Main File in the Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211 19.7 The File Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212 v
19.8 The Edit Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 19.9 The View Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 19.10 The Program Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215 19.11 The Browser Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215 19.12 The Tools Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 19.13 The Distribute Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 19.14 The Help Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 20 Using Other Code Editors 218 20.1 Using Notepad++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 20.2 Using Geany . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219 20.3 Using Atom . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220 20.4 Using Sublime Text 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 20.5 Using Visual Studio IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222 20.6 Using Emacs Editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223 20.7 Visual Studio Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223 21 Variables 225 21.1 Dynamic Typing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 21.2 Deep Copy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 21.3 Weakly Typed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226 22 Operators 227 22.1 Arithmetic Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 22.2 Relational Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 22.3 Logical Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 22.4 Bitwise Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228 22.5 Assignment Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228 22.6 Misc Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228 22.7 Operators Precedence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229 23 Control Structures - First Style 230 23.1 Branching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230 23.2 Looping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231 23.3 Using The Step option with For in . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232 23.4 Using For in to modify lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 23.5 Do Again Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 23.6 Exit Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 23.7 Exit from two loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234 23.8 Loop Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234 23.9 Exit/Loop inside sub functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234 23.10 Short-circuit evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 23.11 Comments about evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 24 Control Structures - Second Style 237 24.1 Branching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 24.2 Looping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238 24.3 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239 25 Control Structures - Third Style 240 25.1 Branching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240 25.2 Looping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 25.3 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 26 Getting Input 245 vi
26.1 Give Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245 26.2 GetChar() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245 26.3 Input() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246 27 Functions - First Style 247 27.1 Define Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247 27.2 Call Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247 27.3 Declare parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248 27.4 Send Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248 27.5 Main Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248 27.6 Variables Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249 27.7 Return Value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249 27.8 Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250 28 Functions - Second Style 251 28.1 Define Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251 28.2 Call Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251 28.3 Declare parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252 28.4 Send Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252 28.5 Main Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252 28.6 Variables Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253 28.7 Return Value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253 28.8 Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254 29 Functions - Third Style 255 29.1 Define Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255 29.2 Call Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255 29.3 Declare parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256 29.4 Send Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256 29.5 Main Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257 29.6 Variables Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257 29.7 Return Value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257 29.8 Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258 30 Program Structure 259 30.1 Source Code File Sections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259 30.2 Using Many Source Code Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259 30.3 Load Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260 31 Lists 261 31.1 Create Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261 31.2 Add Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261 31.3 Get List Size . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262 31.4 Delete Item From List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262 31.5 Get List Item . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262 31.6 Set List Item . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263 31.7 Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263 31.8 Sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264 31.9 Reverse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264 31.10 Insert Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265 31.11 Nested Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265 31.12 Copy Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265 31.13 First-class lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266 31.14 Using Lists during definition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266 31.15 Passing Lists to Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266 vii
31.16 Access List Items by String Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267 31.17 Passing Parameters or Argumnents Using List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267 31.18 Passing Parameters or Argumnents Using List Array . . . . . . . . . . . . . . . . . . . . . . . . . . 268 31.19 Creating a Multi-Dimensional Array using List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268 31.20 Swap Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269 32 Strings 271 32.1 String Literals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271 32.2 Get String Length . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271 32.3 Convert Letters Case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271 32.4 Access String Letters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272 32.5 Left() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272 32.6 Right() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272 32.7 Trim() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273 32.8 Copy() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273 32.9 Lines() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273 32.10 Substr() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274 32.11 Find substring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274 32.12 Get substring from position to end . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274 32.13 Get Number of Characters From Position . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274 32.14 Transform Substring To Another Substring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274 32.15 strcmp() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275 32.16 str2list() and list2str() Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275 32.17 Merge binary characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276 33 Date and Time 278 33.1 Clock() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278 33.2 ClocksPerSecond() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278 33.3 Time() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278 33.4 Date() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279 33.5 TimeList() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279 33.6 AddDays() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280 33.7 DiffDays() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280 33.8 EpochTime() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281 34 Check Data Type and Conversion 282 34.1 Check Data Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282 34.2 IsString() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282 34.3 IsNumber() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282 34.4 IsList() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283 34.5 Type() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283 34.6 IsNULL() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283 34.7 Check Character . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284 34.8 IsAlNum() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284 34.9 IsAlpha() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284 34.10 IsCntrl() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 34.11 IsDigit() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 34.12 IsGraph() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 34.13 IsLower() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 34.14 IsPrint() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286 34.15 IsPunct() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286 34.16 IsSpace() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286 34.17 IsUpper() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286 34.18 IsXdigit() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287 viii
34.19 Conversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287 34.20 Number() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287 34.21 String() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287 34.22 Ascii() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288 34.23 Char() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288 34.24 Hex() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288 34.25 Dec() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288 34.26 Str2hex() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289 34.27 Hex2str() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289 35 Mathematical Functions 290 35.1 List of functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290 35.2 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290 35.3 Random() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292 35.4 SRandom() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293 35.5 Unsigned() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293 35.6 Decimals() Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294 35.7 Using _ in numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294 35.8 Using f after numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295 36 Files 296 36.1 Read() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297 36.2 Write() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297 36.3 Dir() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297 36.4 Rename() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298 36.5 Remove() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298 36.6 Fopen() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298 36.7 Fclose() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299 36.8 Fflush() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299 36.9 Freopen() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299 36.10 Tempfile() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300 36.11 Tempname() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300 36.12 Fseek() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300 36.13 Ftell() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300 36.14 Rewind() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301 36.15 Fgetpos() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301 36.16 Fsetpos() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301 36.17 Clearerr() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301 36.18 Feof() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301 36.19 Ferror() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301 36.20 Perror() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 36.21 Fgetc() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 36.22 Fgets() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 36.23 Fputc() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 36.24 Fputs() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 36.25 Ungetc() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 36.26 Fread() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 36.27 Fwrite() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 36.28 Fexists() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 36.29 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 36.30 Numbers and Bytes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305 37 System Functions 306 37.1 System() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306 ix
37.2 SysGet() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 37.3 IsMSDOS() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 37.4 IsWindows() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 37.5 IsWindows64() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 37.6 IsUnix() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 37.7 IsMacOSX() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308 37.8 IsLinux() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308 37.9 IsFreeBSD() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308 37.10 IsAndroid() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308 37.11 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308 37.12 Windowsnl() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309 37.13 Get Command Line Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309 37.14 Get Active Source File Name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310 37.15 PrevFileName() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310 37.16 CurrentDir() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311 37.17 ExeFileName() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311 37.18 ChDir() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311 37.19 ExeFolder() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311 37.20 Version() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311 37.21 Shutdown() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312 38 Eval() and Debugging 313 38.1 Try/Catch/Done . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313 38.2 Eval() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313 38.3 Raise() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314 38.4 Assert() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315 39 Demo Programs 316 39.1 Language Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316 39.2 Main Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317 40 ODBC Functions 320 40.1 odbc_init() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320 40.2 odbc_drivers() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321 40.3 odbc_datasources() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321 40.4 odbc_close() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321 40.5 Print List of ODBC Drivers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321 40.6 Print List of ODBC Data Sources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322 40.7 odbc_connect() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323 40.8 odbc_disconnect() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323 40.9 Open and Close Connection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323 40.10 odbc_execute() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323 40.11 odbc_colcount() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323 40.12 odbc_fetch() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324 40.13 odbc_getdata() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324 40.14 Execute Query and Print Result . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324 40.15 odbc_tables() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324 40.16 odbc_columns() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325 40.17 odbc_autocommit() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326 40.18 odbc_commit() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326 40.19 odbc_rollback() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326 40.20 Transactions and Using Commit and Rollback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326 40.21 Save and Restore images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327 41 MySQL Functions 329 x
41.1 MySQL_Info() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329 41.2 MySQL_Init() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 41.3 MySQL_Error() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 41.4 MySQL_Connect() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 41.5 MySQL_Close() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 41.6 MySQL_Query() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 41.7 Create Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331 41.8 Create Table and Insert Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331 41.9 MySQL_Insert_ID() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332 41.10 MySQL_Result() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333 41.11 MySQL_Next_Result() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333 41.12 Print Query Result . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333 41.13 MySQL_Columns() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333 41.14 MySQL_Result2() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334 41.15 MySQL_Escape_String() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335 41.16 Save Image inside the database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335 41.17 Restore Image From The Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336 41.18 MySQL_AutoCommit() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336 41.19 MySQL_Commit() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336 41.20 MySQL_Rollback() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336 41.21 Transaction Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336 42 SQLite Functions 338 42.1 sqlite_init() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338 42.2 sqlite_open() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338 42.3 sqlite_execute() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338 42.4 sqlite_close() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338 42.5 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339 43 PostgreSQL Functions 341 43.1 Loading the library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341 43.2 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341 43.3 RingPostgreSQL Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344 43.4 RingPostgreSQL Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345 44 Security and Internet Functions 348 44.1 MD5() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348 44.2 SHA1() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349 44.3 SHA256() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349 44.4 SHA512() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349 44.5 SHA384() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350 44.6 SHA224() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350 44.7 Encrypt() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350 44.8 Decrypt() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351 44.9 Encryption and Decryption Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351 44.10 File Hash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352 44.11 Randbytes() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352 44.12 Download() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352 44.13 SendEmail() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353 45 Object Oriented Programming (OOP) 354 45.1 Classes and Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354 45.2 Access Objects Using Braces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356 45.3 Composition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357 45.4 Setter and Getter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358 xi
45.5 Private Attributes and Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358 45.6 Operator Overloading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359 45.7 Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362 45.8 Dynamic Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363 45.9 Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363 45.10 Printing Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364 45.11 Find() and List of Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364 45.12 Sort() and List of Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365 45.13 Using Self.Attribute and Self.Method() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367 45.14 Using This.Attribute and This.Method() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367 45.15 Using This in the class region as Self . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368 45.16 Default value for object attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369 46 Functional Programming 370 46.1 Pure Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370 46.2 First-class Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371 46.3 Higher-order Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371 46.4 Anonymous and Nested Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372 46.5 Equality of functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373 47 Reflection and Meta-programming 375 47.1 locals() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376 47.2 globals() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376 47.3 functions() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377 47.4 cfunctions() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377 47.5 islocal() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378 47.6 isglobal() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378 47.7 isfunction() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379 47.8 iscfunction() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379 47.9 packages() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379 47.10 ispackage() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 380 47.11 classes() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381 47.12 isclass() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381 47.13 packageclasses() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382 47.14 ispackageclass() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382 47.15 classname() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383 47.16 objectid() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383 47.17 isobject() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384 47.18 attributes() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384 47.19 methods() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384 47.20 isattribute() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385 47.21 isprivateattribute() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385 47.22 ismethod() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386 47.23 isprivatemethod() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386 47.24 addattribute() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387 47.25 addmethod() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387 47.26 getattribute() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389 47.27 setattribute() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390 47.28 mergemethods() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391 47.29 packagename() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392 48 Stdlib Functions 393 48.1 Puts() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393 48.2 Print() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393 xii
48.3 Print2Str() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394 48.4 GetString() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394 48.5 GetNumber() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394 48.6 AppPath() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394 48.7 JustFilePath() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394 48.8 JustFileName() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395 48.9 Value() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395 48.10 Times() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395 48.11 Map() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396 48.12 Filter() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396 48.13 Split() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396 48.14 SplitMany() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397 48.15 NewList() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397 48.16 Capitalized() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397 48.17 IsSpecial() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398 48.18 IsVowel() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398 48.19 LineCount() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398 48.20 Factorial() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398 48.21 Fibonacci() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399 48.22 IsPrime() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399 48.23 Sign() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399 48.24 List2File() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400 48.25 File2List() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400 48.26 StartsWith() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400 48.27 EndsWith() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400 48.28 GCD() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401 48.29 LCM() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401 48.30 SumList() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401 48.31 ProdList() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402 48.32 EvenOrOdd() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402 48.33 Factors() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402 48.34 IsPalindrome() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403 48.35 IsLeapYear() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403 48.36 BinaryDigits() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403 48.37 MatrixMulti() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404 48.38 MatrixTrans() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404 48.39 DayOfWeek() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404 48.40 Permutation() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405 48.41 ReadLine() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405 48.42 SubString() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405 48.43 ChangeString() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406 48.44 Sleep() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406 48.45 IsMainSourceFile() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406 48.46 DirExists() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407 48.47 MakeDir() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407 48.48 Fsize() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407 48.49 TrimAll() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407 48.50 TrimLeft() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408 48.51 TrimRight() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408 48.52 EpochTime() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408 48.53 SystemCmd() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408 48.54 ListAllFiles() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408 48.55 SystemSilent() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409 48.56 OSCreateOpenFolder() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409 xiii
48.57 OSCopyFolder() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409 48.58 OSDeleteFolder() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409 48.59 OSCopyFile() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 48.60 OSDeleteFile() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 48.61 OSRenameFile() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 48.62 List2Code() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 48.63 Str2ASCIIList() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 48.64 ASCIIList2Str() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411 49 Stdlib Classes 412 49.1 StdBase Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412 49.2 String Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413 49.3 List Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415 49.4 Stack Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417 49.5 Queue Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417 49.6 HashTable Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418 49.7 Tree Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419 49.8 Math Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420 49.9 DateTime Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424 49.10 File Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425 49.11 System Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426 49.12 Debug Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427 49.13 DataType Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 428 49.14 Conversion Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429 49.15 ODBC Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 430 49.16 MySQL Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431 49.17 SQLite Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 432 49.18 PostgreSQL Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433 49.19 Security Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435 49.20 Internet Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435 50 Declarative Programming using Nested Structures 436 50.1 Creating Objects inside Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436 50.2 Composition and Returning Objects and Lists by Reference . . . . . . . . . . . . . . . . . . . . . . 437 50.3 Executing code after the end of object access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439 50.4 Declarative Programming on the top of Object-Oriented . . . . . . . . . . . . . . . . . . . . . . . . 439 50.5 More beautiful Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440 51 Natural Language Programming 442 51.1 History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442 51.2 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442 51.3 Change the Ring Keyword ‘And’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443 51.4 Change the Ring Operator ‘+’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444 51.5 Change the ‘=’ operator to ‘is’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445 51.6 Using Eval() with our Natural Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446 51.7 BraceStart and BraceEnd Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 447 51.8 BraceExprEval Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448 51.9 Real Natural Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448 51.10 BraceError() Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449 51.11 Clean Natural Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450 52 Using the Natural Library 452 52.1 Natural Library - Demo Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452 52.2 Defining Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454 52.3 Natural Library - Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457 xiv
52.4 Defining commands using classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457 53 Web Development (CGI Library) 459 53.1 Configure the Apache web server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459 53.2 Ring CGI Hello World Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460 53.3 Hello World Program using the Web Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460 53.4 Web Library Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461 53.5 HTTP Get Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461 53.6 HTTP POST Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466 53.7 Upload Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 468 53.8 Cookies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471 53.9 URL Encode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473 53.10 Templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474 53.11 HTML Special Characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476 53.12 Hash Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 477 53.13 Random Image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 479 53.14 HTML Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480 53.15 HTML Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 482 53.16 Gradient . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 483 53.17 Generating Pages using Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 484 53.18 HtmlPage Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 488 53.19 Using Bootstrap Library using Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 489 53.20 Using Bootstrap Library using Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490 53.21 CRUD Example using MVC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493 53.22 Users registration and Login . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 495 53.23 Database, ModelBase & ControllerBase classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 501 53.24 WebLib API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506 53.25 Application Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 508 53.26 Page Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 508 53.27 ScriptFunctions Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 510 53.28 StyleFunctions Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 511 53.29 WebPage Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 511 53.30 HtmlPage Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 512 54 Deploying Web Applications in the Cloud 513 54.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513 54.2 Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513 54.3 Ring source code files and permissions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 514 54.4 Hello World program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 515 54.5 Application Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 515 54.6 Deploying after updates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 515 54.7 Local Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516 55 Using RingLibCurl 517 55.1 Get Request . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517 55.2 Post Request . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517 55.3 Facebook Login . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517 55.4 Save Output to String . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 518 55.5 Get Stock Data From Yahoo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519 56 Using RingZip 521 56.1 Create Zip File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 521 56.2 Extract Zip File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 521 56.3 Print Files in Zip file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 521 56.4 Using RingZip Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 521 xv
56.5 Zip Class Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 523 56.6 ZipEntry Class Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 523 57 Graphics and 2D Games programming using RingAllegro 524 57.1 Drawing, Animation and Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 524 57.2 Using TrueType Fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 531 57.3 Playing Sound Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 532 57.4 Scaling and Rotating Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 533 57.5 Display Transparent Image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534 57.6 Using Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 535 58 Using RingLibSDL 538 58.1 Create Window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 538 58.2 Display Image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 538 58.3 Switch between two images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539 58.4 Draw Rectangle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539 58.5 Display PNG Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540 58.6 Use TTF Fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540 58.7 Display Transparent Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540 58.8 Close Window Event . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 541 58.9 Mouse Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 542 58.10 Play Sound . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 543 59 Using RingLibuv 545 59.1 First Application using RingLibuv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 545 59.2 The Events Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546 59.3 Server Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546 59.4 Client Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 548 59.5 Server Example Using Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 549 59.6 Client Example Using Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 550 59.7 Threads Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 551 59.8 Threads Example - Using Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 552 60 Demo Project - Game Engine for 2D Games 553 60.1 Project Layers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 553 60.2 Graphics Library bindings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 553 60.3 Interface to graphics library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 554 60.4 Game Engine Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 554 60.5 Games Layer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 554 60.6 Game Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 555 60.7 GameObject Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 555 60.8 Sprite Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 556 60.9 Text Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 556 60.10 Animate Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557 60.11 Sound Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557 60.12 Map Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557 60.13 Using the Game Engine - Creating the Game Window . . . . . . . . . . . . . . . . . . . . . . . . . 558 60.14 Using the Game Engine - Drawing Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 558 60.15 Using the Game Engine - Moving Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 559 60.16 Using the Game Engine - Playing Sound . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561 60.17 Using the Game Engine - Animation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 562 60.18 Using the Game Engine - Animation and Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 563 60.19 Using the Game Engine - Sprite - Automatic Movement using Keyboard . . . . . . . . . . . . . . . 565 60.20 Using the Game Engine - Sprite - Keypress event . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566 60.21 Using the Game Engine - Sprite - Mouse event . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566 xvi
60.22 Using the Game Engine - Sprite - State event . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567 60.23 Using the Game Engine - Animate - Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 568 60.24 Using the Game Engine - Map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 570 60.25 Using the Game Engine - Map Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 572 60.26 Using the Game Engine - Object and Drawing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 573 60.27 Stars Fighter Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 576 60.28 Flappy Bird 3000 Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 584 60.29 Super Man 2016 Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 591 61 Building Games For Android 603 61.1 Download Requirements and Update the Android SDK . . . . . . . . . . . . . . . . . . . . . . . . . 603 61.2 Project Folder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 603 61.3 Building the project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 604 62 Using RingOpenGL and RingFreeGLUT for 3D Graphics 606 62.1 Samples Source (Authors) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606 62.2 What is RingOpenGL? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606 62.3 What is RingFreeGLUT? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 607 62.4 The First Window using RingFreeGLUT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 607 62.5 Drawing using RingOpenGL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 608 62.6 The First Triangle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 610 62.7 Window Resize Event . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 611 62.8 Triangle Rotation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 612 62.9 Keyboard Events and Colors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 613 62.10 The Camera . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 616 62.11 Mouse Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 623 62.12 Menu Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 626 62.13 Using Fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 633 62.14 Frames Per Second . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 641 62.15 Make a Cube using RingOpenGL and RingFreeGLUT . . . . . . . . . . . . . . . . . . . . . . . . . 650 63 Using RingOpenGL and RingAllegro for 3D Graphics 654 63.1 3D Cube and Texture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 654 63.2 Many Cubes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 658 63.3 TicTacToe 3D Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 664 63.4 More 3D Samples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 673 64 The Gold Magic 800 Game 676 64.1 The Game Story . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 676 64.2 How to play? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 676 64.3 What will you learn? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 676 64.4 Screen Shots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 677 64.5 Source Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 678 65 Desktop and Mobile development using RingQt 680 65.1 The First GUI Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 680 65.2 The Events Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 682 65.3 Using Layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 682 65.4 Using the QTextEdit Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 683 65.5 Using the QListWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 684 65.6 Using QTreeView and QFileSystemModel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 687 65.7 Using QTreeWidget and QTreeWidgetItem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 688 65.8 Using QComboBox Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 690 65.9 Creating Menubar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691 65.10 Context Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 693 xvii
65.11 Creating Toolbar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 694 65.12 Creating StatusBar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 695 65.13 Using QDockWidget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 696 65.14 Using QTabWidget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 697 65.15 Using QTableWidget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 699 65.16 Using QProgressBar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 700 65.17 Using QSpinBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701 65.18 Using QSlider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 702 65.19 Using QDateEdit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 703 65.20 Using QDial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 704 65.21 Using QWebView . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 707 65.22 Using QCheckBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 708 65.23 Using QRadioButton and QButtonGroup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 709 65.24 Adding Hyperlink to QLabel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 711 65.25 QVideoWidget and QMediaPlayer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 712 65.26 Using QFrame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 714 65.27 Display Image using QLabel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 715 65.28 Menubar and StyleSheet Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 716 65.29 QLineEdit Events and QMessageBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 718 65.30 Other Widgets Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 720 65.31 Using the QTimer Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 722 65.32 Using QProgressBar and Timer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 723 65.33 Display Scaled Image using QLabel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 724 65.34 Using the QFileDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 725 65.35 Drawing using QPainter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 726 65.36 Printing using QPrinter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 728 65.37 Using QPrintPreviewDialog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 729 65.38 Creating More than one Window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 731 65.39 Playing Sound . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 732 65.40 Using the QColorDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 733 65.41 Using qLCDNumber Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 734 65.42 Movable Label Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 735 65.43 QMessagebox Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 736 65.44 Using QInputDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 737 65.45 Dialog Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 738 65.46 KeyPress and Mouse Move Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 739 65.47 Moving Objects using the Mouse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 740 65.48 Inheritance from GUI Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 744 65.49 Using QDesktopWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 745 65.50 Rotate Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 746 65.51 Change Focus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 748 65.52 Regular Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 749 65.53 Simple Client and Server Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 750 65.54 Dynamic Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 752 65.55 Weight History Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 753 65.56 Notepad Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 757 65.57 The Cards Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 772 65.58 Classes and their Methods to use the default events . . . . . . . . . . . . . . . . . . . . . . . . . . . 778 65.59 Methods to use Events with Events Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781 65.60 The Difference between Qt and RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 782 65.61 RingQt Classes and their Qt Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 783 65.62 New Classes names - Index Start from 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 783 65.63 Creating Reports using the WebLib and the GUILib . . . . . . . . . . . . . . . . . . . . . . . . . . 784 xviii
66 Building RingQt Applications for Mobile 787 66.1 Download Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 787 66.2 Update the Android SDK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 787 66.3 Install Qt for Android . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 788 66.4 Using Ring2EXE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 788 66.5 The Qt project for your Ring application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 788 66.6 Comments about developing for Android using RingQt . . . . . . . . . . . . . . . . . . . . . . . . . 789 67 Objects Library for RingQt Application 791 67.1 Library Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791 67.2 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791 67.3 Open_WindowAndLink() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 794 67.4 Open_WindowInPackages() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 795 67.5 Objects Library Source Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 795 68 Using the Form Designer 796 68.1 The Designer Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 797 68.2 The Toolbox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 797 68.3 The Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 797 68.4 Running Forms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 798 68.5 Events Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 798 68.6 Keyboard Shortcuts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 801 68.7 Menubar Designer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 801 68.8 Window Flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 802 68.9 Entering Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 803 68.10 Using Layouts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 803 68.11 More Samples and Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 803 69 Multi-language Applications 804 69.1 Using String2Constant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 804 69.2 Form Designer Translation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 805 69.3 Forms Translation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 806 70 Scope Rules for Variables and Attributes 808 70.1 Three Scopes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 808 70.2 Defining Variables and Variables Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 808 70.3 How Ring find the variable? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 809 70.4 Using Object.Attribute . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 809 70.5 The Self Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 809 70.6 How Ring Define Variables and Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 810 70.7 Conflict between Global Variables and Class Attributes . . . . . . . . . . . . . . . . . . . . . . . . . 810 70.8 Conflict between Class Attributes and Local Variables . . . . . . . . . . . . . . . . . . . . . . . . . 811 70.9 Using Braces to access objects inside Class Methods . . . . . . . . . . . . . . . . . . . . . . . . . . 812 70.10 Accessing the class attributes from braces inside class methods . . . . . . . . . . . . . . . . . . . . 815 70.11 Creating a Class for each Window in GUI applications . . . . . . . . . . . . . . . . . . . . . . . . . 816 70.12 Conflict between self inside braces and self in the class region . . . . . . . . . . . . . . . . . . . . . 817 70.13 Using braces to escape from the current object scope . . . . . . . . . . . . . . . . . . . . . . . . . . 820 70.14 The For Loops uses the local scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 821 70.15 Summary of Scope Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 821 71 Scope Rules for Functions and Methods 824 71.1 How Ring find the Functions and Methods? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 824 71.2 Example about Sharing Names between Functions and Methods . . . . . . . . . . . . . . . . . . . . 825 71.3 Calling a function sharing the name with a method in the current class . . . . . . . . . . . . . . . . . 826 xix
72 Syntax Flexibility 828 72.1 Change Language Keywords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 828 72.2 Change Language Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 829 72.3 Load Syntax Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 830 72.4 Using “()” around the function parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 831 72.5 Using Semi-colon after and between statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 831 72.6 Using $ and @ in the start of the variable name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 832 72.7 Using the ‘elseif’ keyword as ‘but’ in if statement . . . . . . . . . . . . . . . . . . . . . . . . . . . 832 72.8 Using the ‘else’ keyword as ‘other’ in switch statement . . . . . . . . . . . . . . . . . . . . . . . . . 833 72.9 Using the ‘end’ keyword in different control structures . . . . . . . . . . . . . . . . . . . . . . . . . 833 72.10 Using braces to start and end different control structures . . . . . . . . . . . . . . . . . . . . . . . . 834 72.11 Using ‘put’ and ‘get’ as ‘see’ and ‘give’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 835 72.12 Using ‘case’ as ‘on’ in switch statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 835 72.13 Using ‘def’ as ‘func’ in functions/methods definition . . . . . . . . . . . . . . . . . . . . . . . . . . 836 72.14 Using braces { } in Packages/Classes/Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 836 72.15 Using ‘end’ keyword after Packages/Classes/Functions . . . . . . . . . . . . . . . . . . . . . . . . . 836 72.16 Using ‘endpackage’/’endclass’/’endfunc’ keywords after Packages/Classes/Functions . . . . . . . . 837 72.17 Ignore new lines after keywords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 837 73 Introduction to the Type Hints Library 838 73.1 Why Type Hints? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 838 73.2 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 838 73.3 User Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 838 73.4 Using Types inside Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 839 73.5 Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 839 74 Command Line Options 841 74.1 Printing Tokens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 841 74.2 Printing Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 843 74.3 Printing Intermediate Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 847 74.4 Printing Final Intermediate Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 850 74.5 CGI Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 854 74.6 No Run . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 854 74.7 Printing Instruction Operation Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 854 74.8 Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 854 74.9 Generate Object File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 855 75 Performance Tips 856 75.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 856 75.2 Creating Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 858 75.3 Arithmetic Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 859 75.4 Using len() and For Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 859 75.5 Calling Functions and Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 860 76 Distributing Ring Applications 862 76.1 Distributing Applications for Microsoft Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . 862 76.2 Protecting the Source Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 862 76.3 The files ring.ring and ring.ringo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 863 76.4 Creating Windows Installer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 863 76.5 Using C/C++ Compiler and Linker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 863 76.6 Distributing Applications and Games for Mobile . . . . . . . . . . . . . . . . . . . . . . . . . . . . 863 77 Distributing Ring Applications using Ring2EXE 864 77.1 Using Ring2EXE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 864 77.2 How Ring2EXE works? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 864 xx
77.3 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 865 77.4 Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 865 77.5 Building standalone console application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 866 77.6 Distributing RingAllegro Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 866 77.7 Distributing RingQt Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 867 77.8 Distributing Applications for Mobile using RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . 867 77.9 Building the Cards Game for Mobile using RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . 868 77.10 Building the Weight History Application for Mobile using RingQt . . . . . . . . . . . . . . . . . . . 868 77.11 Building the Form Designer for Mobile using RingQt . . . . . . . . . . . . . . . . . . . . . . . . . 869 77.12 Creating the Qt resource file using Folder2qrc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 871 77.13 Important Information about Ring2EXE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 871 78 The Ring Package Manager (RingPM) 873 78.1 Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 873 78.2 Discovering Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 873 78.3 Updating the RingPM Registry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 874 78.4 Installing Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 874 78.5 Printing List of Installed Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 875 78.6 Run Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 875 78.7 Update Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 876 78.8 Remove Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 876 78.9 Deleting All Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 876 78.10 Creating New Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 876 78.11 The Package Description File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 878 78.12 Create Package in the Current Folder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 879 78.13 The RingPM Registry File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 881 79 Low Level Functions 883 79.1 callgc() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 884 79.2 varptr() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 884 79.3 space() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 885 79.4 nullpointer() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 885 79.5 object2pointer() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 885 79.6 pointer2object() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 886 79.7 ispointer() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 886 79.8 ptrcmp() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 887 79.9 ringvm_cfunctionslist() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 887 79.10 ringvm_functionslist() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 887 79.11 ringvm_classeslist() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 888 79.12 ringvm_packageslist() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 889 79.13 ringvm_memorylist() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 890 79.14 ringvm_calllist() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 892 79.15 ringvm_fileslist() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 892 79.16 ringvm_settrace() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 893 79.17 ringvm_tracedata() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 893 79.18 ringvm_traceevent() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 894 79.19 ringvm_tracefunc() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 894 79.20 ringvm_scopescount() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 894 79.21 ringvm_evalinscope() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 895 79.22 ringvm_passerror() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 895 79.23 ringvm_hideerrormsg() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 895 79.24 ringvm_callfunc() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 895 79.25 Example - Using the Trace Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 895 79.26 Example - The Trace Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 899 xxi
79.27 ringvm_see() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 903 79.28 ringvm_give() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 903 79.29 ringvm_info() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 903 80 The Trace Library and the Interactive Debugger 905 80.1 Loading the Trace library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 905 80.2 Trace All Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 905 80.3 Trace control flow between functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 905 80.4 Pass Error . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 906 80.5 Interactive Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 906 80.6 Execute Program Line by Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 906 80.7 BreakPoint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 907 80.8 Disable BreakPoints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 907 80.9 Using the Interactive Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 907 81 Embedding Ring in Ring 910 81.1 Embedding Ring in Ring without sharing the State . . . . . . . . . . . . . . . . . . . . . . . . . . . 910 81.2 Serial Execution of Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 911 81.3 ring_state_setvar() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 911 81.4 ring_state_new() and ring_state_mainfile() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 912 81.5 Runtime Errors when Embedding Ring in Ring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 913 82 Extension using the C/C++ languages 914 82.1 ring_ext.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 914 82.2 ring_ext.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 914 82.3 Module Organization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 915 82.4 Function Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 916 82.5 Check Parameters Count . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 916 82.6 Display Error Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 917 82.7 Check Parameters Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 917 82.8 Get Parameters Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 917 82.9 Return Value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 918 82.10 Function Prototype . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 918 82.11 Sin() Function Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 918 82.12 Fopen() and Fclose() Functions Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 918 82.13 Ring API - List Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 919 82.14 Ring API - String Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 921 82.15 MySQL_Columns() Function Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 921 82.16 Dynamic/Shared Libraries (DLL/So/Dylib) and LoadLib() function . . . . . . . . . . . . . . . . . . 922 82.17 Using RING_API_RETMANAGEDCPOINTER() . . . . . . . . . . . . . . . . . . . . . . . . . . . 923 83 Embedding Ring Language in C/C++ Programs 925 83.1 Ring State . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 925 83.2 Ring State Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 925 83.3 Ring State Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 926 84 Code Generator for wrapping C/C++ Libraries 928 84.1 Using the tool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 928 84.2 Configuration file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 928 84.3 Using the function prototype . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 928 84.4 Adding code to the generated code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 930 84.5 Prefix for Functions Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 930 84.6 Generate function to wrap structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 930 84.7 Determine Structure Members Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 931 84.8 Defining Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 931 xxii
84.9 Register New Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 931 84.10 Writing comments in the configuration file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 932 84.11 Executing code during code generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 932 84.12 Enum and Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 932 84.13 Filtering using Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 933 84.14 Constants Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 933 84.15 Configuration file for the Allegro Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 933 84.16 Threads Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 935 84.17 Code Generator Rules for Wrapping C++ Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 936 84.18 Using configuration file that wrap C++ Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 937 84.19 Configuration file for the Qt Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 937 84.20 Static Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 947 84.21 Loading Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 947 84.22 Managed Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 947 84.23 Configuration Files Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 948 85 Create your first extension 949 85.1 Location . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 949 85.2 Steps to create the extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 949 85.3 Testing the extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 950 86 Frequently Asked Questions (FAQ) 951 86.1 Why do we need Yet Another Programming Language (YAPL)? . . . . . . . . . . . . . . . . . . . . 951 86.2 Why is Ring weakly typed? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 952 86.3 What are the advantages to using Ring over Lisp or Smalltalk? . . . . . . . . . . . . . . . . . . . . . 952 86.4 Why is Ring largely focussed on UI creation? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 953 86.5 Is Ring some sort of an improvement of PHP? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 953 86.6 What are the advantages of using Ring over native C or C++? . . . . . . . . . . . . . . . . . . . . . 953 86.7 What is the difference between Ring and Python? And is Ring Open Source? . . . . . . . . . . . . . 953 86.8 What are the advantages to using Ring over Perl, PHP, Python or Ruby? . . . . . . . . . . . . . . . . 954 86.9 What are the advantages to using Ring over Tcl or Lua? . . . . . . . . . . . . . . . . . . . . . . . . 955 86.10 What are the advantages to using Ring over C# or Java? . . . . . . . . . . . . . . . . . . . . . . . . 955 86.11 The documentation says functional programming is supported, but then this happens? . . . . . . . . 955 86.12 Why the ability to define your own languages Instead of just handing over the syntax so you can parse it using whatever code you like? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 956 86.13 Why you can specify the number of loops you want to break out of? . . . . . . . . . . . . . . . . . . 956 86.14 Why Ring uses ‘See’, ‘Give’, ‘But’ and ‘Ok’ Keywords? . . . . . . . . . . . . . . . . . . . . . . . . 956 86.15 What is the philosophy behind data types in Ring? . . . . . . . . . . . . . . . . . . . . . . . . . . . 957 86.16 What about the Boolean values in Ring? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 957 86.17 What is the goal of including the “Main” function in Ring? . . . . . . . . . . . . . . . . . . . . . . . 958 86.18 Why the list index start from 1 in Ring? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 959 86.19 Why Ring is not case-sensitive? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 959 86.20 Why the Assignment operator uses Deep Copy? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 960 86.21 Is there constructor methods in Ring? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 961 86.22 What happens when we create a new object? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 961 86.23 Can we use the attributes by accessing the Getter and Setter methods? . . . . . . . . . . . . . . . . . 962 86.24 Why should a search of global names be made while defining the class attributes? . . . . . . . . . . 963 86.25 Why Ring doesn’t avoid the conflict between Global Variables and Class Attributes Names? . . . . . 964 86.26 Where can I write a program and execute it? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 965 86.27 How to get the file size using ftell() and fseek() functions? . . . . . . . . . . . . . . . . . . . . . . . 965 86.28 How to get the current source file path? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 965 86.29 What about predefined parameters or optional parameters in functions? . . . . . . . . . . . . . . . . 965 86.30 How to print keys or values only in List/Dictionary? . . . . . . . . . . . . . . . . . . . . . . . . . . 966 86.31 Why I get a strange result when printing nl with lists? . . . . . . . . . . . . . . . . . . . . . . . . . 966 xxiii
86.32 Could you explain the output of the StrCmp() function? . . . . . . . . . . . . . . . . . . . . . . . . 967 86.33 How to use many source code files in the project? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 967 86.34 Why this example use the GetChar() twice? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 968 86.35 How to use NULL and ISNULL() function? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 969 86.36 How to print lists that contains objects? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 970 86.37 How to insert an item to the first position in the list? . . . . . . . . . . . . . . . . . . . . . . . . . . 971 86.38 How to print new lines and other characters? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 971 86.39 Why we don’t use () after the qApp class name? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 971 86.40 Why the window title bar is going outside the screen? . . . . . . . . . . . . . . . . . . . . . . . . . 972 86.41 How to create an array of buttons in GUI applications? . . . . . . . . . . . . . . . . . . . . . . . . . 972 86.42 How to Close a window then displaying another one? . . . . . . . . . . . . . . . . . . . . . . . . . . 973 86.43 How to create a Modal Window? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 973 86.44 How can I disable maximize button and resize window? . . . . . . . . . . . . . . . . . . . . . . . . 974 86.45 How to use SQLite using ODBC? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 975 86.46 Can I connect to dbase/harbour database? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 976 86.47 Why setClickEvent() doesn’t see the object methods directly? . . . . . . . . . . . . . . . . . . . . . 977 86.48 Why I get Calling Function without definition Error? . . . . . . . . . . . . . . . . . . . . . . . . . . 977 86.49 Can Ring work on Windows XP? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 978 86.50 How to extend RingQt and add more classes? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 978 86.51 How to add Combobox and other elements to the cells of a QTableWidget? . . . . . . . . . . . . . . 981 86.52 How to perform some manipulations on selected cells in QTableWidget? . . . . . . . . . . . . . . . 981 86.53 Which of 3 coding styles are commonly used or recommended by the community? . . . . . . . . . . 982 87 General Information 983 87.1 Ring Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 983 87.2 Memory Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 983 87.3 Data Representation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 984 88 Language Reference 987 88.1 Language Keywords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 987 88.2 Language Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 989 88.3 Compiler Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 990 88.4 Runtime Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 990 88.5 Environment Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 992 88.6 Language Grammar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 992 88.7 Virtual Machine (VM) Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 993 89 RingQt Classes Reference 1000 89.1 CodeEditor Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1000 89.2 QAbstractButton Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1000 89.3 QAbstractItemView Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1001 89.4 QAbstractPrintDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1003 89.5 QAbstractScrollArea Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1003 89.6 QAbstractSlider Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1004 89.7 QAbstractSocket Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1005 89.8 QAbstractSpinBox Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1006 89.9 QAction Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1007 89.10 QAllEvents Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1009 89.11 QApp Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1013 89.12 QAxBase Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1013 89.13 QAxObject Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1015 89.14 QAxWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1015 89.15 QBitmap Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1015 89.16 QBluetoothAddress Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1015 xxiv
89.17 QBluetoothDeviceDiscoveryAgent Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1016 89.18 QBluetoothDeviceInfo Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1016 89.19 QBluetoothHostInfo Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1017 89.20 QBluetoothLocalDevice Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1017 89.21 QBluetoothServer Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1018 89.22 QBluetoothServiceDiscoveryAgent Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1018 89.23 QBluetoothServiceInfo Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1019 89.24 QBluetoothSocket Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1020 89.25 QBluetoothTransferManager Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1021 89.26 QBluetoothTransferReply Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1021 89.27 QBluetoothTransferRequest Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1021 89.28 QBluetoothUuid Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1022 89.29 QBoxLayout Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1022 89.30 QBrush Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1023 89.31 QBuffer Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1023 89.32 QButtonGroup Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1023 89.33 QByteArray Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1024 89.34 QCalendarWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1026 89.35 QCamera Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1027 89.36 QCameraImageCapture Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1028 89.37 QCameraViewfinder Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1029 89.38 QChar Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1029 89.39 QCheckBox Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1031 89.40 QChildEvent Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1032 89.41 QClipboard Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1032 89.42 QColor Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1032 89.43 QColorDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1035 89.44 QComboBox Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1035 89.45 QCompleter Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1037 89.46 QCompleter2 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1038 89.47 QCompleter3 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1038 89.48 QCoreApplication Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1038 89.49 QCursor Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1040 89.50 QDate Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1040 89.51 QDateEdit Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1041 89.52 QDateTime Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1041 89.53 QDateTimeEdit Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1042 89.54 QDesktopServices Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1043 89.55 QDesktopWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1044 89.56 QDial Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1044 89.57 QDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1045 89.58 QDir Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1045 89.59 QDirModel Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1047 89.60 QDockWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1048 89.61 QDrag Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1049 89.62 QDragEnterEvent Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1049 89.63 QDragLeaveEvent Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1049 89.64 QDragMoveEvent Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1050 89.65 QDropEvent Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1050 89.66 QEvent Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1050 89.67 QFile Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1051 89.68 QFile2 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1051 89.69 QFileDevice Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1052 89.70 QFileDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1052 xxv
89.71 QFileInfo Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1053 89.72 QFileSystemModel Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1055 89.73 QFont Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1056 89.74 QFontDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1058 89.75 QFontMetrics Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1058 89.76 QFrame Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1059 89.77 QFrame2 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1060 89.78 QFrame3 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1060 89.79 QGeoAddress Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1060 89.80 QGeoAreaMonitorInfo Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1061 89.81 QGeoAreaMonitorSource Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1061 89.82 QGeoCircle Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1061 89.83 QGeoCoordinate Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1062 89.84 QGeoPositionInfo Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1062 89.85 QGeoPositionInfoSource Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1063 89.86 QGeoRectangle Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1063 89.87 QGeoSatelliteInfo Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1064 89.88 QGeoSatelliteInfoSource Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1064 89.89 QGeoShape Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1064 89.90 QGradient Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1065 89.91 QGraphicsVideoItem Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1065 89.92 QGridLayout Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1065 89.93 QGuiApplication Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1066 89.94 QHBoxLayout Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1068 89.95 QHeaderView Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1068 89.96 QHostAddress Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1071 89.97 QHostInfo Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1071 89.98 QIODevice Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1072 89.99 QIcon Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1073 89.100QImage Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1073 89.101QInputDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1074 89.102QJsonArray Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1076 89.103QJsonDocument Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1076 89.104QJsonObject Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1077 89.105QJsonParseError Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1077 89.106QJsonValue Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1078 89.107QKeySequence Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1078 89.108QLCDNumber Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1078 89.109QLabel Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1079 89.110QLayout Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1080 89.111QLineEdit Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1081 89.112QLinearGradient Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1083 89.113QListView Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1083 89.114QListWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1084 89.115QListWidgetItem Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1085 89.116QMainWindow Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1086 89.117QMatrix4x4 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1088 89.118QMdiArea Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1089 89.119QMdiSubWindow Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1090 89.120QMediaObject Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1091 89.121QMediaPlayer Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1091 89.122QMediaPlaylist Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1092 89.123QMenu Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1092 89.124QMenuBar Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1093 xxvi
89.125QMessageBox Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1094 89.126QMimeData Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1095 89.127QMutex Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1096 89.128QMutexLocker Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1096 89.129QNetworkAccessManager Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1096 89.130QNetworkProxy Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1097 89.131QNetworkReply Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1098 89.132QNetworkRequest Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1098 89.133QNmeaPositionInfoSource Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1099 89.134QObject Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1099 89.135QOpenGLBuffer Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1100 89.136QOpenGLContext Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1100 89.137QOpenGLDebugLogger Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1101 89.138QOpenGLFramebufferObject Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1102 89.139QOpenGLFunctions Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1102 89.140QOpenGLFunctions_3_2_Core Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1107 89.141QOpenGLPaintDevice Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1114 89.142QOpenGLShader Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1115 89.143QOpenGLShaderProgram Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1115 89.144QOpenGLTexture Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1119 89.145QOpenGLTimerQuery Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1121 89.146QOpenGLVersionProfile Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1121 89.147QOpenGLVertexArrayObject Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1122 89.148QOpenGLWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1122 89.149QPageSetupDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1123 89.150QPaintDevice Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1123 89.151QPainter Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1123 89.152QPainter2 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1126 89.153QPainterPath Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1126 89.154QPen Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1127 89.155QPicture Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1128 89.156QPixmap Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1128 89.157QPixmap2 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1130 89.158QPlainTextEdit Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1130 89.159QPoint Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1132 89.160QPointF Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1133 89.161QPrintPreviewDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1133 89.162QPrintPreviewWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1133 89.163QPrinter Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1134 89.164QPrinterInfo Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1136 89.165QProcess Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1136 89.166QProgressBar Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1137 89.167QPushButton Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1138 89.168QQmlError Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1138 89.169QQuaternion Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1139 89.170QQuickWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1139 89.171QRadioButton Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1140 89.172QRect Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1140 89.173QRegion Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1142 89.174QRegularExpression Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1143 89.175QRegularExpressionMatch Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1143 89.176QRegularExpressionMatchIterator Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1144 89.177QScreen Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1144 89.178QScrollArea Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1145 xxvii
89.179QScrollBar Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1146 89.180QSerialPort Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1146 89.181QSerialPortInfo Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1147 89.182QSize Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1148 89.183QSlider Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1148 89.184QSpinBox Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1148 89.185QSplashScreen Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1149 89.186QSplitter Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1149 89.187QSqlDatabase Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1150 89.188QSqlDriver Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1151 89.189QSqlDriverCreatorBase Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1152 89.190QSqlError Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1152 89.191QSqlField Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1152 89.192QSqlIndex Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1153 89.193QSqlQuery Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1153 89.194QSqlRecord Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1154 89.195QStackedWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1155 89.196QStandardPaths Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1156 89.197QStatusBar Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1156 89.198QString2 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1156 89.199QStringList Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1157 89.200QStringRef Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1158 89.201QSurfaceFormat Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1160 89.202QSystemTrayIcon Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1161 89.203QTabBar Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1161 89.204QTabWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1163 89.205QTableView Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1164 89.206QTableWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1166 89.207QTableWidgetItem Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1168 89.208QTcpServer Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1169 89.209QTcpSocket Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1170 89.210QTest Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1170 89.211QTextBlock Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1170 89.212QTextBrowser Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1171 89.213QTextCharFormat Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1172 89.214QTextCodec Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1174 89.215QTextCursor Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1174 89.216QTextDocument Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1176 89.217QTextEdit Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1178 89.218QTextStream Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1180 89.219QTextStream2 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1182 89.220QTextStream3 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1182 89.221QTextStream4 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1182 89.222QTextStream5 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1182 89.223QThread Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1182 89.224QThreadPool Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1183 89.225QTime Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1184 89.226QTimer Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1184 89.227QToolBar Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1185 89.228QToolButton Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1186 89.229QTreeView Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1186 89.230QTreeWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1188 89.231QTreeWidgetItem Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1191 89.232QUrl Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1192 xxviii
89.233QUuid Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1193 89.234QVBoxLayout Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1193 89.235QVariant Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1194 89.236QVariant2 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1195 89.237QVariant3 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1195 89.238QVariant4 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1195 89.239QVariant5 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1195 89.240QVector2D Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1196 89.241QVector3D Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1196 89.242QVector4D Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1197 89.243QVideoWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1198 89.244QVideoWidgetControl Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1198 89.245QWebEngineView Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1198 89.246QWebView Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1200 89.247QWebView Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1200 89.248QWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1201 89.249QWindow Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1206 89.250QXmlStreamAttribute Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1210 89.251QXmlStreamAttributes Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1210 89.252QXmlStreamEntityDeclaration Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1211 89.253QXmlStreamEntityResolver Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1211 89.254QXmlStreamNamespaceDeclaration Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1211 89.255QXmlStreamNotationDeclaration Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1211 89.256QXmlStreamReader Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1212 89.257QXmlStreamWriter Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1213 89.258RingCodeHighlighter Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1214 90 RingMurmurHash Functions Reference 1215 90.1 MurmurHash1 functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1215 90.2 MurmurHash2 functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1215 90.3 MurmurHash3 functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1215 90.4 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1216 91 FoxRing Functions Reference 1217 91.1 FoxRing functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1217 91.2 frAbs() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1218 91.3 frAsc() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1218 91.4 frAddBs() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1219 91.5 frAt() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1219 91.6 frAtC() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1220 91.7 frChr() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1220 91.8 frEmpty() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1220 91.9 frFile() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1221 91.10 frFileToStr() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1221 91.11 frStr() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1221 91.12 frSetIfEmpty() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1222 91.13 frSpace() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1223 91.14 frInList() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1223 91.15 frForcePath() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1223 91.16 frAllTrim() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1223 91.17 frLTrim() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1224 91.18 frJustDrive() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1224 91.19 frJustExt() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1224 91.20 frJustStem() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1224 xxix
91.21 frRTrim() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1224 91.22 frJustPath() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1225 91.23 frForceExt() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1225 91.24 frALines() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1225 91.25 frJustFName() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1225 91.26 frPadL() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1225 91.27 frPadR() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1225 91.28 frProper() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1225 91.29 frReplicate() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1225 91.30 frLen() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1226 91.31 frStuff() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1226 91.32 frSubStr() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1226 91.33 frStrTran() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1226 91.34 frListToString() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1226 91.35 frInt() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1227 91.36 frStringToList() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1227 91.37 frIIf() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1227 91.38 frVal() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1227 91.39 frBetween() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1227 91.40 frSetSeparatorTo() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1228 91.41 frTransform() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1228 91.42 frVarType() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1228 91.43 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1229 92 BigNumber Library 1231 92.1 Loading the library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1231 92.2 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1231 92.3 BigNumber Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1232 92.4 BigNumber Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1233 92.5 Library Source Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1233 93 RingLibCurl Functions Reference 1234 94 RingLibZip Functions Reference 1243 95 RingConsoleColors Functions Reference 1244 96 RingAllegro Functions Reference 1246 97 RingLibSDL Functions Reference 1265 98 RingLibuv Functions Reference 1290 99 RingFreeGLUT Functions Reference 1299 100RingOpenGL (OpenGL 1.1) Functions Reference 1308 101RingOpenGL (OpenGL 1.2) Functions Reference 1333 102RingOpenGL (OpenGL 1.3) Functions Reference 1359 103RingOpenGL (OpenGL 1.4) Functions Reference 1388 104RingOpenGL (OpenGL 1.5) Functions Reference 1418 105RingOpenGL (OpenGL 2.0) Functions Reference 1449 xxx
106RingOpenGL (OpenGL 2.1) Functions Reference 1483 107RingOpenGL (OpenGL 3.0) Functions Reference 1525 108RingOpenGL (OpenGL 3.1) Functions Reference 1570 109RingOpenGL (OpenGL 3.2) Functions Reference 1616 110RingOpenGL (OpenGL 3.3) Functions Reference 1663 111RingOpenGL (OpenGL 4.0) Functions Reference 1709 112RingOpenGL (OpenGL 4.1) Functions Reference 1756 113RingOpenGL (OpenGL 4.2) Functions Reference 1803 114RingOpenGL (OpenGL 4.3) Functions Reference 1850 115RingOpenGL (OpenGL 4.4) Functions Reference 1897 116RingOpenGL (OpenGL 4.5) Functions Reference 1944 117RingOpenGL (OpenGL 4.6) Functions Reference 1991 118Resources 2039 118.1 Ring Language Website . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2039 118.2 Ring Group . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2039 118.3 Source Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2039 118.4 Arabic Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2039 118.5 Contact the Authors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2040 Index 2041 xxxi
CHAPTER ONE APPLICATIONS DEVELOPED IN LITTLE 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. It’s just released in 2016.01.25! In little days 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 little 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.” , 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 1
Ring Documentation, Release 1.10 “Very interesting effort.” , Giannakakis Kostas (Greece) “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) “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 1.1. Quotes about Ring 2
Ring Documentation, Release 1.10 “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) “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. Why bother with C/C++ when the syntax can be cryptic and they are largely antiquated - why should we still be dealing with header files, etc? Moreover, your comments on Java and C# being too verbose and forcing OOP onto the user is spot on as well - yet these languages are still primarily used by millions of programmers for the most mundane tasks. At this point, I’m led to believe that it’s simply a matter of legacy applications that still haven’t made the transition, as well as the ever-popular “Appeal to Popularity” fallacy shared by many in academia and enterprise. Then we come to languages, that are easier and much more modern, and yet even now, are being to show their age. Languages like Python which stresses whitespace and indentation, as well as (just like the formerly mentioned languages) irrelevant tokens for the conditional statements. Granted, it’s not as bad as tracking down various curly braces or semi-colons, but one misstep in indentation might as well be as frustrating to track down. The same could be true of Ruby, except with Ruby, we have even odder conventions embedded into the design of the language, which I don’t feel the need to address and moreover, we’re left with something like Lua which is missing a great many features that the previously mentioned languages include. There are many more languages and faults with them, we could claim that PHP is nothing more than a glue for web pages and backends but with so many frameworks available now, it’s falling by the wayside fast. Javascript is constantly being cloned. So, each of these general purpose languages, which we all know are mostly domain-specific and in some cases, also oriented at certain OS(C# was before 2016 and Obj-C/Swift will likely always be primarily for MacOS apps). So, then we’re left with several additional options, involving everything from hybrids to other imperative-based languages like D, GoLang, Scala, Julia, etc. But finally, there’s a new language called Ring - and yes, it may just end up ruling them all. It’s the unicorn we’ve finally been waiting to arrive, that can handle multiple domains, tasks, and paradigms. I honestly can’t wait to jump in and when I do I probably won’t come back up anytime soon. My only apprehension is that the language may not include a library or primitive functions for math as Python and Julia do. Aside from that, if so, hopefully, I won’t be having to use linear expressions as arrays (considering how intellectually lazy it is to do) and that there will be more support/tools as the community continues to grow. It’s crazy to think it’s only been around for a year and yet, it’s already, practically a batteries-included language.” 1.1. Quotes about Ring 3
Ring Documentation, Release 1.10 , 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) “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.” , Nuaua (Reddit) “The code that implements the Ring VM actually looks quite nice. There is a bunch of test code – great!” , Pe- terfirefly (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 i , Wim ten Brink (Quora - Top Writer (2018)) “Interesting alternative to Lua.” , djxtc (Sourceforge) 1.1. Quotes about Ring 4
Ring Documentation, Release 1.10 “Ring is a serious thing in the programming language landscape. One shoud 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 distruption, 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 todays 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 intutively. 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 assesing 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 1.2 FetchStockData Application URL : https://groups.google.com/forum/#!topic/ring-lang/-fa1U_SXSjo Author : Bert Mariani This App is written in Ring. It will fetch stock data from Yahoo and draw various types of charts. Any valid stock ticker can be entered, or selected from the drop down list - Select Symbol. It will not guarantee that you make money in the stock market. But it will visualize the history of the stock. 1.2. FetchStockData Application 5
Ring Documentation, Release 1.10 1.3 Fifteen Puzzle Game 2 URL : https://github.com/ring-lang/ring/blob/master/applications/fifteenpuzzle/CalmoSoftFifteenPuzzleGame.ring Author : Gal Zsolt (CalmoSoft) 1.3. Fifteen Puzzle Game 2 6
Ring Documentation, Release 1.10 1.3. Fifteen Puzzle Game 2 7
Ring Documentation, Release 1.10 1.4 Google API Shortener Application Author : John Storm (SienSystem) Hi everyone, Wanted to (finally) share a first release version of a small but very nice tool to shorten urls using the Google shortener API. The code is fully documented, maybe too documented, but, provides a good reference as to what is going on. You can obtain your own API key, or you can use my key to test and use the tool. Hope you enjoy the application. Please feel free to test at your convenience. Ring is FUN!! 1.4. Google API Shortener Application 8
Ring Documentation, Release 1.10 1.5 Analog Clock URL : https://github.com/ring-lang/ring/blob/master/applications/analogclock/AnalogClock-Image.ring Author : Bert Mariani 1.6 TicTacToe Game URL : https://github.com/AbdelrahmanGIT/RingSamples/blob/master/src/TecTacToe.ring Author : Abdelrahman Mohammed 1.5. Analog Clock 9
Ring Documentation, Release 1.10 1.7 Squares Puzzle Game URL : https://github.com/MajdiSobain/RingAllegro_SquaresPuzzle Author : Majdi Sobain This project is about (Squares Puzzle) popular game that I have programmed using ring language with its RingAllegro Library. The principle of this game is very known to all of us, which is moving squares to get the real full shape of the original picture. This game could be played using mouse and keyboard as well, showing a message of congratulations at the successful solving. 1.7. Squares Puzzle Game 10
Ring Documentation, Release 1.10 1.8 Video-Music-Player Application Author : Bert Mariani Screen Shot: 1.8. Video-Music-Player Application 11
Ring Documentation, Release 1.10 1.9 Calculator Application Author : Magdy Ragab Updated Version by Gal Zsolt and Bert Mariani Screen Shot: 1.9. Calculator Application 12
Ring Documentation, Release 1.10 1.10 Windows StartUp Manager Application URL : https://github.com/ring-lang/WinStartupManager Author : Majdi Sobain Windows Startup Manager is an application that has the ability to let the user control what programs should start at Windows booting time. It gives you the ability to show, edit, delete, or even add new programs entries to be lunched at Windows booting time. It is specialized at managing Windows startup entries that are stored in Windows Registry only, but provides a quick option to edit programs shortcuts type entries. Screen Shot: 1.10. Windows StartUp Manager Application 13
Ring Documentation, Release 1.10 1.11 Werdy Application URL : https://github.com/ring-lang/werdy Author : Magdy Ragab Quran application includes reading suras, searching and bookmarking. The applcation is provided for Windows, Linux and Android. 1.11. Werdy Application 14
Ring Documentation, Release 1.10 1.12 Samples in this book The next samples are developed in little hours and we will introduce them through this book. The next screen shot for he Ring Notepad application 1.12. Samples in this book 15
Ring Documentation, Release 1.10 The next screen shot for the Cards Game The next screen shot for the Cards Game (Android) 1.12. Samples in this book 16
Ring Documentation, Release 1.10 The next screen shot from the Web Development chapter 1.12. Samples in this book 17
Ring Documentation, Release 1.10 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.12. Samples in this book 18
Ring Documentation, Release 1.10 Super Man 2016 Game 1.12. Samples in this book 19
Ring Documentation, Release 1.10 The next screen shot for the TicTacToe 3D Game Screen Shot: 1.12. Samples in this book 20
Ring Documentation, Release 1.10 The next screen shot for the Gold Magic 800 Game 1.12. Samples in this book 21
Ring Documentation, Release 1.10 1.13 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.14 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/applications/formdesigner 1.13. Innovative 22
Ring Documentation, Release 1.10 We can run the Form Designer as Android application! 1.14. Practical 23
CHAPTER TWO INTRODUCTION Welcome to the Ring 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 create Console, GUI, Web, Games and Mobile applications. The language is designed to be Simple, Small, Flexible and Fast. Its Dynamic Language (Dynamic Typing and Weakly Typed) 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. Most of the PWCT source code was written in VFP and the software comes with a simple scripting language for creating the components called (RPWI). The software contains components that support code generation in pro- gramming languages like Harbour, C, Supernova & Python. 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 & can be used for developing different kinds of applications. Instead of using a mix of programming languages, I decided to use one programming language for creating the devel- opment environment, for components scripting & for creating the applications. I looked at many programming languages like C, C++, Java, C#, Lua, PHP, Python & Ruby. I avoided using C or C++ directly because I want high-level of productivity more than the level provided by these languages, also a language behind visual programming environment for novice programmers or professionals must be easy to use & productive. 24
Ring Documentation, Release 1.10 Java & C# are avoided for some reason too! I wanted to use a dynamic programming language and these languages are static typing, Java is multi-platform, also C# through Mono, but the use of huge number of classes and forcing the use of Object-Orientation, using a verbose language is not right for me. I need a small language, but fast and productive, also I need better control on the Garbage Collector (GC), I need a better one that is designed for fast applications. Lua is small and fast, but it’s avoided because I need more powerful language for large applications. PHP is a Web programming language and it’s syntax is very similar to C, this leads to a language not general as I want and not simple as I need to have. Python & Ruby are more like what I need, but I need something more simple, smaller, faster & productive. Python and Ruby are Case-Sensitive, the list index start counting from 0, you have to define the function before calling it, Ruby usage of Object-Orientation and message passing is more than what I need and decrease performance, Python syntax (indentation, using self, :, pass & _) is not good for my goals. All of these languages are successful languages, and very good for their domains, but what I need is a different language that comes with new ideas and intelligent implementation (Innovative, Ready, Simple, Small, Flexible and Fast). 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 Special Thanks to Matz Special Thanks to Matz (Yukihiro Matsumoto - The Creator of Ruby Programming Language) for spreading the word. 2.2. Ring and other languages 25
Ring Documentation, Release 1.10 2.4 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 2.4. History 26
Ring Documentation, Release 1.10 2.5 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) • Writen 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 • 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) • Use exit to go outside from loop in the Caller function (Use it for programming in the small only) 2.5. Features 27
Ring Documentation, Release 1.10 • 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 • List functions • File processing functions • Database support (ODBC, SQLite, MySQL & PostgreSQL) • Security Functions (OpenSSL) • Internet Functions (LibCurl) • Zip Functions 2.5. Features 28
Ring Documentation, Release 1.10 • 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 • 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) • Tracing and Debugging • Type Hints Library • Comes with Ring2EXE to distribute applications • RingLibuv 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. Features 29
Ring Documentation, Release 1.10 2.6 License The Ring Programming Language http://ring-lang.net/ Version 1.10 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.6. License 30
CHAPTER THREE LANGUAGE DESIGN In this chapter we will learn about the basic concepts behind the language design. 3.1 Why Ring? The language is simple, trying to be natural, encourage organization and comes with transparent and visual implemen- tation. It comes with compact syntax and a group of features that enable the programmer to create natural interfaces and declarative domain-specific languages in a fraction of time. It is very small, fast and comes with smart garbage collector that puts the memory under the programmer control. It supports many programming paradigms, comes with useful and practical libraries. The language is designed for productivity and developing high quality solutions that can scale. 3.2 Designed for a Clear Goal • Applications programming language. • Productivity and developing high quality solutions that can scale. • Small and fast language that can be embedded in C/C++ projects. • Simple language that can be used in education and introducing Compiler/VM concepts. • General-Purpose language that can be used for creating domain-specific libraries, frameworks and tools. • Practical language designed for creating the next version of the Programming Without Coding Technology software. 3.3 Simple Ring is a very simple language, and has a very straightforward syntax. It encourages programmers to program without boilerplate code See "Hello, World!" The Main function is optional and will be executed after the statements, and is useful for using the local scope. Func Main See "Hello, World!" 31
Ring Documentation, Release 1.10 Uses Dynamic Typing and Lexical scoping. No $ is required before the variable name! You can use the ‘+’ operator for string concatenation and the language is weakly typed and will convert automatically between numbers and strings based on the context. nCount = 10 # Global variable Func Main nID = 1 # Local variable See "Count = " + nCount + nl + " ID = " + nID 3.4 Trying to be natural Ring is not case-sensitive See "Enter your name ? " Give name See "Hello " + Name # Name is the same as name The list index starts from 1 aList = ["one","two","three"] See aList[1] # print one Call functions before definition one() two() three() Func one See "One" + nl Func two See "two" + nl Func three See "three" + nl The assignment operator uses Deep copy (no references in this operation) aList = ["one","two","three"] aList2 = aList aList[1] = 1 see alist[1] # print 1 see aList2[1] # print one Pass numbers and strings by value, but pass lists and objects by reference. The for in loop can update the list items. Func Main aList = [1,2,3] update(aList) see aList # print one two three Func update aList for x in aList switch x on 1 x = "one" on 2 x = "two" on 3 x = "three" off next 3.4. Trying to be natural 32
Ring Documentation, Release 1.10 Using Lists during definition 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 Exit from more than one loop 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 3.5 Encourage Organization The language encourage organization, Forget bad days using languages where the programmer start with function then class then function and a strange mix between things! Each source file follow the next structure • Load Files • Statements and Global Variables • Functions • Packages and Classes This enable us to use Packages, Classes and Functions without the need to use a keyword to end these components. We can write one line comments and multi-line comments The comment starts with # or // Multi-line comments are written between /* and */ /* Program Name : My first program using Ring Date : 2015.05.08 */ See "What is your name? " # print message on screen give cName # get input from the user see "Hello " + cName # say hello! // See "Bye!" 3.6 Compact Syntax The language is not line sensitive, you don’t need to write ; after statements, also you don’t need to press ENTER or TAB, so we can write the next code See "The First Message" See " Another message in the same line! " + nl See "Enter your name?" Give Name See "Hello " + Name The next code create a class called Point contains three attributes X,Y and Z. No keywords is used to end the pack- age/class/function definition. Also, we can write the attributes names directly below the class name. 3.5. Encourage Organization 33
Ring Documentation, Release 1.10 Class Point X Y Z We can use classes and functions before their definition, In this example we will create new object, set the object attributes then print the object values. o1 = New point o1.x=10 o1.y=20 o1.z=30 See O1 Class Point X Y Z Instead of using the dot ‘.’ operator to access the object attributes and methods we can use braces { } to access the object, then we can use the object attributes and methods. o1 = New point { x=10 y=20 z=30 } See O1 Class Point X Y Z Now we will call a method after accessing the object using { } oPerson = new Person { Name = "Somebody" Address = "Somewhere" Phone = "0000000" Print() # here we call the Print() method } Class Person Name Address Phone Func Print See "Name :" + name + nl + "Address :" + Address + nl + "Phone : " + phone + nl When we use { } to access the object then write any attribute name, the language will check the class for any set- ter/getter methods that will be called automatically. New Number { See one # Execute GetOne() See two # Execute GetTwo() See three # Execute GetThree() } Class Number one two three Func GetOne See "Number : One" + nl return 1 Func GetTwo See "Number : Two" + nl return 2 Func GetThree See "Number : Three" + nl return 3 3.7 Define Natural Statements After the object access using { } if the class contains a method called BraceEnd() it will be executed! TimeForFun = new journey # The first surprise! TimeForFun { Hello it is me # What a beatiful programming world! } # Our Class Class journey 3.7. Define Natural Statements 34
Ring Documentation, Release 1.10 hello=0 it=0 is=0 me=0 func GetHello See "Hello" + nl func braceEnd See "Goodbye!" + nl We can execute code written in strings using the Eval() function cCode = "See 'Code that will be executed later!' " Eval(cCode) # execute the code to print the message We can create a list then execute code generated from that list aWords = ["hello","it","is","me"] for word in aWords cCode=word+"=0" eval(cCode) next We can read text files using the Read(cFileName) function and we can write files using the Write(cFileName,cString) function. See "Enter File Name:" Give cFileName See Read(cFileName) # Print the file content The next example presents how to create a class that defines two instructions The first instruction is : I want window The second instruction is : Window title = Expression 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 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++ 3.7. Define Natural Statements 35
Ring Documentation, Release 1.10 ok func settitle cValue if nWindowTitle = 1 nWindowTitle=0 see "Instruction : Window Title = " + cValue + nl ok To complete the previous example, use read() to get the content of a file that contains I want window The window title = "hello world" Then use eval() to execute the content of that file!. Also, you can update the methods GetWindow() and SetTitle() to create Real windows using the GUI Library 3.8 Define Declarative Languages We learned how to use Natural statements to execute our code and using the same features we can use nested structures to execute our code. The next example from the Web library, generate HTML document using the Bootstrap library. No HTML code is written directly in this example, we created a similar language (just as example) Then using this declarative language that uses nested structures, we generated the HTML Document.. The idea in this example is that the GetDiv() and GetH1() methods return an object that we can access using {} and after each object access the method BraceEnd() will be executed to send the generated HTML to the parent object until we reach to the root where BraceEnd() will print the output. 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 } } } 3.8. Define Declarative Languages 36
Ring Documentation, Release 1.10 The classes that power the declarative interface looks like this Class Link from ObjsBase title link Func braceend cOutput = nl+GetTabs() + "<a href='" + Link + "'> "+ Title + " </a> " + nl Class Div from ObjsBase Func braceend cOutput += nl+'<div' addattributes() AddStyle() getobjsdata() cOutput += nl+"</div>" + nl cOutput = TabMLString(cOutput) 3.9 Syntax Flexibility Ring comes with many styles for writing your source code! Also you can change the language keywords and operators and create your custom style! 3.10 Transparent Implementation Ring comes with transparent implementation. We can know what is happening in each compiler stage and what is going on during the run-time by the Virtual Machine Example : ring helloworld.ring -tokens -rules -ic See "Hello, World!" Output ================================================================== Tokens - Generated by the Scanner ================================================================== Keyword : SEE Literal : Hello, World! EndLine ================================================================== ================================================================== Grammar Rules Used by The Parser ================================================================== Rule : Program --> {Statement} Line 1 Rule : Factor --> Literal Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift 3.9. Syntax Flexibility 37
Ring Documentation, Release 1.10 Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> 'See' Expr ================================================================== ================================================================== Byte Code - Before Execution by the VM ================================================================== PC OPCode Data 1 FuncExE 2 PushC Hello, World! 3 Print 4 ReturnNull ================================================================== Hello, World! 3.11 Visual Implementation The Ring programming language is designed using the PWCT visual programming tool and you will find the visual source of the language in the folder “visualsrc” - *.ssf files and the generated source code (In the C Language) in the src folder and the include folder. The next screen shot from the ring_vm.ssf file (Generate ring_vm.c and ring_vm.h) 3.11. Visual Implementation 38
Ring Documentation, Release 1.10 The next screen shot from the ring_list.ssf file (Generate ring_list.c and ring_list.h) 3.12 Smart Garbage Collector Avoid memory problems :- • Invalid Memory Access • Memory leaks • Uninitialized Memory Access • Dangling pointer Rules :- • Global variables always stay in the memory, until you delete these variables using the assignment statement. • Local variables always deleted after the end of the function. • The programmer have full control on when to delete the variable from the memory using the Assignment state- ment. Example: aList = [1,2,3,4,5] aList = "nice" After the second line directly, The list [1,2,3,4,5] will be deleted from the memory and we will have a string “nice” • The programmer can call the function callgc() to force running the garbage collector. • If we have a reference to a variable (when we pass objects and lists to functions), then deleting variables will be based on reference counting, if no references everything will be deleted, but if we have a reference, the data will stay in memory. 3.12. Smart Garbage Collector 39
Ring Documentation, Release 1.10 3.13 No Global Interpreter (VM) Lock - No GIL When we use threads in Ring applications, We don’t have global interpreter (VM) lock (No GIL) So threads can work in parallel and execute Ring instructions at the same time This is better for threads and concurrency (More Faster!) 3.14 Fast Enough For Many Applications 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! 3.13. No Global Interpreter (VM) Lock - No GIL 40
CHAPTER FOUR WHAT IS NEW IN RING 1.10? In this chapter we will learn about the changes and new features in Ring 1.10 release. 4.1 List of changes and new features Ring 1.10 comes with the next features! • Chess Game • Minesweeper Game • Knight Tour Game • Game of Life Game • Pong Game • Snakes and Ladder Game • More Games • Ring Extension for Visual Studio Code • The Ring Package Manager (RingPM) • Better Tests • More Improvements 4.2 Chess Game Chess Game (2 Players) 41
Ring Documentation, Release 1.10 4.3 Minesweeper Game The objective of the game is to clear a rectangular board containing hidden “mines” or bombs without detonating any of them. 4.3. Minesweeper Game 42
Ring Documentation, Release 1.10 4.4 Knight Tour Game Move to every square on the chess board, using only the moves of a knight. Can you visit every square in just 63 moves? 4.4. Knight Tour Game 43
Ring Documentation, Release 1.10 4.5 Game of Life Game The game is a zero-player game, meaning that its evolution is determined by its initial state, requiring no further input. One interacts with the Game of Life by creating an initial configuration and observing how it evolves, or, for advanced players, by creating patterns with particular properties. 4.5. Game of Life Game 44
Ring Documentation, Release 1.10 4.6 Pong Game Simple “tennis like” game features two paddles and a ball. The goal is to defeat your opponent once the opponent misses a ball. 4.6. Pong Game 45
Ring Documentation, Release 1.10 4.7 Snakes And Ladder Game The Snakes and Ladder Game using Ring Game Engine for 2D Games 4.7. Snakes And Ladder Game 46
Ring Documentation, Release 1.10 4.8 More Games The next games are added to the application folder • Lights Out Game • Dots and Boxes Game • Magic Four Game • Sum Puzzle Game The next screen shot for the Sum Puzzle Game 4.8. More Games 47
Ring Documentation, Release 1.10 4.9 Ring Extension for Visual Studio Code This extension support the Ring programming language in Visual Studio Code 4.9. Ring Extension for Visual Studio Code 48
Ring Documentation, Release 1.10 4.10 The Ring Package Manager (RingPM) Ring comes with a package manager (RingPM) that we can use to install, update and remove packages. 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 =========================================================================== 4.11 Better Tests New framework for Ring programming language tests that test the language. 4.10. The Ring Package Manager (RingPM) 49
Ring Documentation, Release 1.10 4.12 More Improvements 1. Ring Compiler : Better support for (Operator Operator) to avoid checking the first operator when it’s a literal. 2. Ring Compiler : When we load a file that doesn’t exist, display the caller file name in the error message. 3. Ring Compiler : Support source code files with one line of comment without end of line. 4. Ring Compiler : change nNoAssignment attribute in Parser Structure to nNewObject. 5. Ring VM : Better support for the (Return) command inside braces that access new objects. 6. Ring VM : Dir() Function - Don’t add ”.” and ”..” to the output 7. Ring VM : Dir() Function - Correct output for the item type (file|directory) on Linux and macOS. 8. Ring VM : ICO_LISTSTART - Clean pVM->aSetProperty when setting an object attribute. 9. Ring VM : ICO_NEWOBJECT - Clean pVM->aSetProperty when setting an object attribute. 10. Ring VM : Better code for Setter and Getter methods support. 11. Ring2EXE: The libraries information are stored in separated files in ring/ring2exe/libs folder. 12. WebLib : Separate the library to many source code files. 13. StdLib : IsVowel() function - Better Code. 14. RingQt : Count(), Left(), Mid() and Right() methods are added to QString class. 15. Better Read Me File 4.12. More Improvements 50
CHAPTER FIVE WHAT IS NEW IN RING 1.9? In this chapter we will learn about the changes and new features in Ring 1.9 release. 5.1 List of changes and new features Ring 1.9 comes with the next features! • New Game : Gold Magic 800 • More Games • Better Ring Notepad • Better StdLib • BigNumber Library • RingPostgreSQL Extension • Deploying Web applications in the Cloud • Better RingQt • Better Memory Management • Better Code Generator for Extensions • More Improvements 5.2 New Game : Gold Magic 800 The Gold Magic 800 is a new puzzle game. Ring 1.9 comes with the Demo Version (18 Levels) and the game source code. Steam Page (44 Levels) : https://store.steampowered.com/app/939200/Gold_Magic_800/ We can select the level 51
Ring Documentation, Release 1.10 The next screen shot for level (1) The Gold Magic 800 Level Editor 5.2. New Game : Gold Magic 800 52
Ring Documentation, Release 1.10 5.3 More Games The next games are added to Ring Applications 1. The 2048 Game 2. The Memory Game 3. The Wise Quadrat Game 4. The Tessera Game 5. The Othello Game The next screen shot for the 2048 game on Android 5.3. More Games 53
Ring Documentation, Release 1.10 The next screen shot for the Tessera game 5.3. More Games 54
Ring Documentation, Release 1.10 The next screen shot for the Othello game 5.3. More Games 55
Ring Documentation, Release 1.10 5.4 Better Ring Notepad 1. New Style 2. New Mode 3. Tabs for opened files 4. Support executing batch files 5.4. Better Ring Notepad 56
Ring Documentation, Release 1.10 5.5 Better StdLib 1. The List2Code() function is added to the StdLib 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 ] 2. The Str2ASCIIList() and ASCIIList2Str() are added to the StdLib Using these functions we can convert between string of bytes and a list of numbers where each item represent the ASCII code of one byte in the string. So we may convert a string of bytes to ASCII List then do some operations on the list numbers (Like XOR) Example: load "stdlibcore.ring" cStr = "MmMm" aList = Str2ASCIILIST(cStr) ? aList 5.5. Better StdLib 57
Ring Documentation, Release 1.10 cStr2 = ASCIIList2Str(aList) ? cStr2 ? len(cStr2) Output: 77 109 77 109 MmMm 4 5.6 BigNumber Library Using the BigNumber library we can do arithmetic operations on huge numbers. Example: load "bignumber.ring" num1 = "62345678901234567891678345123456789" ### Big num2 = "1237894567890123419871236545" ### Small num3 = "64" ### Divide Small num4 = "765432" num5 = "3" ### Power ? "Add big numbers:" a1 = new BigNumber(num1) a1.Print() a2 = new BigNumber(num2) a2.Print() a3 = a1 + a2 a3.Print() ? nl ? "Substract big numbers:" a1 = new BigNumber(num1) a1.Print() a2 = new BigNumber(num2) a2.Print() a3 = a1 - a2 a3.Print() ? nl ? "Multiply big numbers:" a1 = new BigNumber(num1) a1.print() a2 = new BigNumber(num2) a2.print() a3 = a1 * a2 a3.print() ? nl ? "Divide big numbers:" a1 = new BigNumber(num1) a1.print() a2 = new BigNumber(num2) a2.print() a3 = a1 / a2 a3.print() ? nl ? "Divide big numbers: by very small number" a1 = new BigNumber(num1) a1.print() a2 = new BigNumber(num3) a2.print() a3 = a1 / a2 a3.print() ? nl ? "Power of big number:" a1 = new BigNumber(num1) a1.print() a2 = new BigNumber(num5) a2.print() 5.6. BigNumber Library 58
Ring Documentation, Release 1.10 a3 = a1 ^ a2 a3.print() ? nl Output: Add big numbers: 62345678901234567891678345123456789 1237894567890123419871236545 62345680139129135781801764994693334 Substract big numbers: 62345678901234567891678345123456789 1237894567890123419871236545 52345687663340000001554925252220244 Multiply big numbers: 62345678901234567891678345123456789 1237894567890123419871236545 77177377243260150103462178714197454736432472780119682305154005 Divide big numbers: 62345678901234567891678345123456789 1237894567890123419871236545 50364288 Divide big numbers: by very small number 62345678901234567891678345123456789 64 974151232831790123307474142554012 Power of big number: 62345678901234567891678345123456789 3 242336636261471172092347146031727004 (Output continue in next line) 371698195628343934238988256152289508 (Output continue in next line) 493964611043228971692389860897069 For more information check the BigNumber Library Chapter in the documentation 5.7 RingPostgreSQL Extension Ring 1.9 provide native support for PostgreSQL database using the RingPostgreSQL Extension. Example: load "postgresqllib.ring" conninfo = "user=postgres password=sa dbname = mahdb" exit_nicely = func conn { PQfinish(conn) shutdown(1) } 5.7. RingPostgreSQL Extension 59
Ring Documentation, Release 1.10 conn = PQconnectdb(conninfo) if (PQstatus(conn) != CONNECTION_OK) fputs(stderr, "Connection to database failed: "+PQerrorMessage(conn)) call exit_nicely(conn) ok 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) 5.7. RingPostgreSQL Extension 60
Ring Documentation, Release 1.10 ok nFields = PQnfields(res) for i = 1 to nFields ? 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 For more information check the PostgreSQL Chapter in the documentation 5.8 Deploying Web applications in the Cloud 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/ 5.8. Deploying Web applications in the Cloud 61
Ring Documentation, Release 1.10 For more information check the Deploying Web Applications In The Cloud chapter in the documentation. 5.9 Better RingQt 1. The next classes are added to RingQt • QDrag • QMimeData • QDropEvent • QDragMoveEvent • QDragEnterEvent • QDragLeaveEvent • QClipboard • QChildEvent • QGeoPositionInfo • QGeoCoordinate • QGeoAddress • QGeoAreaMonitorInfo • QGeoAreaMonitorSource • QGeoCircle • QGeoPositionInfoSource 5.9. Better RingQt 62
Ring Documentation, Release 1.10 • QGeoRectangle • QGeoShape • QGeoSatelliteInfo • QGeoSatelliteInfoSource • QNmeaPositionInfoSource • QAxWidget • QTextStream • QPrinterInfo • QPrintPreviewWidget • QPrintPreviewDialog • QPageSetupDialog • QAbstractPrintDialog • QPrintDialog 2. The next classes are updated • QAllEvents Class : New Events (ChildAdded, ChildPolished, ChildRemoved). • QPainter Class : Updated Methods (drawConvexPloygon, drawPoints, drawPolyline) Accept Ring list of points. • QVariant : More versions that accept different parameters when creating the object. • QAxBase : Different versions for the dynamicCall() and querySubObject() methods. The next example for using 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 printer1 { painter = new qpainter() { begin(printer1) myfont = new qfont("Times",50,-1,0) setfont(myfont) drawtext(100,100,"Test - Page (1)") printer1.newpage() 5.9. Better RingQt 63
Ring Documentation, Release 1.10 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: 5.9. Better RingQt 64
Ring Documentation, Release 1.10 5.10 Better Memory Management The Ring API is updated to include RING_API_RETMANAGEDCPOINTER() Using RING_API_RETMANAGEDCPOINTER() the Ring extensions written in C/C++ languages can return a man- aged pointer to Ring. This pointer can be controlled by the Ring VM using reference counting. 5.10. Better Memory Management 65
Ring Documentation, Release 1.10 This is important to avoid the need to write code that free the unmanaged resources like QPixMap objects in RingQt. Also the Code Generator for extensions is updated to automatically use RING_API_RETMANAGEDCPOINTER() based on need. Syntax: RING_API_RETMANAGEDCPOINTER(void *pValue,const char *cPointerType, void (* pFreeFunc)(void *,void *)) For more information about RING_API_RETMANAGEDCPOINTER() See the “Extension using the C/C++ languages” Chapter in the documentation 5.11 Better Code Generator for Extensions 1. The code generator for extensions is updated to support the <loadfile> command <loadfile> filename.cf This is useful to separate the extension configuraition file to many files Example: The file : qt_module_network.cf in the RingQt Extension <comment> Module (network) </comment> <loadfile> qabstractsocket.cf <loadfile> qnetworkproxy.cf <loadfile> qtcpsocket.cf <loadfile> qtcpserver.cf <loadfile> qhostaddress.cf <loadfile> qhostinfo.cf <loadfile> qnetworkrequest.cf <loadfile> qnetworkaccessmanager.cf <loadfile> qnetworkreply.cf 2. The code generator support the <managed> option when defining classes. Using this option, the generator will use RING_API_RETMANAGEDCPOINTER() to return the C pointer. So the Garabage Collector will manage these C pointers. Example <class> name: QFont para: QString, int, int, bool managed </class> 5.12 More Improvements 1. Ring Compiler - The Rule (Factor -> ‘-‘ Expr) changed to (Factor -> ‘-‘ Factor). 2. Ring VM - Better Error Message. 5.11. Better Code Generator for Extensions 66
Ring Documentation, Release 1.10 3. Better code for IsNULL() function - updated to check pointers too. 4. Better code for ringvm_evalinscope() function - used by the Trace Library. 5. Better code for Space() function. 6. Better code for Hex() and Dec() functions. 7. Better code for Download() function. 8. Better code for SubStr() function. 9. Better code for the Unsigned() function. 10. Better code for Chdir() function. 11. Better code for Tempname() function. 12. Better code for HashTable - New Key (using ring_strdup() instead of strdup() function). 13. New Function : SRandom() - Initialize random number generator. 14. New Function : IsPointer(). 15. IsList() will not return True for C Pointers, we have now the IsPointer() function. 16. The ? Operator is updated to respect the ringvm_see() function. 17. Scripts to run Ring tests on Linux and macOS (Not only Windows). 18. RingAllegro is Updated from Allegro 5.1 to Allegro 5.2. 19. Shader Functions are added to RingAllegro. 20. Joystick Functions are added to RingAllegro. 21. Network functions are added to RingLibSDL. 22. Game Engine for 2D Games - Text Class - Check the font object before usage. 23. Game Engine for 2D Games - Automatic support for Joystick. 24. RingLibCurl is updated to automatically use CURLOPT_COPYPOSTFIELDS when needed. 25. Ring Notepad - Find Previous Feature. 26. Ring Notepad - Default Style. 27. Ring Notepad - Support using Non-English language (Like Arabic) in file names. 28. Form Designer - Nice Aliginment for Toolbox Icons. 29. Form Desginer - QAllEvents Class - Mouse Double Click Event. 30. Find in Files - Replace and Replace All options. 31. Qt Class Converter is updated for better conversion results. 32. More samples are added to ring/samples/other folder. 33. Code Refactoring for Ring Notepad, RingQt, Game Engine for 2D Games. 34. Better Documentation - Many images are updated to reflect the current state of Ring Environment. 35. Better Documentation - More chapters are added to the documentation. 5.12. More Improvements 67
CHAPTER SIX WHAT IS NEW IN RING 1.8? In this chapter we will learn about the changes and new features in Ring 1.8 release. 6.1 List of changes and new features Ring 1.8 comes with the next features! • Better Performance • Find in files Application • String2Constant Application • StopWatch Application • More 3D Samples • Compiling on Manjaro Linux • Using This in the class region as Self • Default value for object attributes is NULL • The For Loops uses the local scope • Merge binary characters • FoxRing Library • Better Form Designer • Better Cards Game • Better RingQt • Better Code Generator For Extensions • Better Ring Compiler and VM • Notes to extensions creators 6.2 Better Performance Ring 1.8 is faster than Ring 1.7 The performance gain is between 10% and 100% based on the application. Check the 3D samples in this release to get an idea about the current performance. 68
Ring Documentation, Release 1.10 For more information check the Performance Tips chapter. 6.3 Find in files Application Ring 1.8 comes with Find in files application 6.4 String2Constant Application Ring 1.8 comes with String2Constant application 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 the Arabic language. For more information check the Multi-language Applications chapter. 6.3. Find in files Application 69
Ring Documentation, Release 1.10 6.5 StopWatch Application Ring 1.8 comes with StopWatch application 6.5. StopWatch Application 70
Ring Documentation, Release 1.10 6.6 More 3D Samples Ring 1.8 comes with more 3D Samples The next screen shot for the Top-Down view - Many levels of cubes sample 6.6. More 3D Samples 71
Ring Documentation, Release 1.10 The next screen shot for the Camera Sample The next screen shot for the Camera and background sample Developer : Azzeddine Remmal 6.6. More 3D Samples 72
Ring Documentation, Release 1.10 6.7 Compiling on Manjaro Linux Ring 1.8 is tested on Manjaro Linux too Tests by : Iip Rifai 6.7. Compiling on Manjaro Linux 73
Ring Documentation, Release 1.10 6.8 Using This in the class region as Self The class region is the region that comes after the class name and before any method. Now 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 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. 6.8. Using This in the class region as Self 74
Ring Documentation, Release 1.10 6.9 Default value for object attributes is NULL Starting from Ring 1.8 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 In previous versions of Ring, trying to access the object attribute before assigning a value to it Will lead to runtime error and you can’t check it using isnull() The only way was assigning a value or using try/catch/end We changed this behavior so we can have full control in seamless way. 6.10 The For Loops uses the local scope In 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 6.9. Default value for object attributes is NULL 75
Ring Documentation, Release 1.10 ? 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 6.11 Merge binary characters From Ring 1.0 we can create binary strings and do operations on these strings. Now in 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 ? "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: 6.11. Merge binary characters 76
Ring Documentation, Release 1.10 Weo Weo 3 W All String 12 First Part 4 Second Part 4 } Third Part 4 All String 12 1 1 6.12 FoxRing Library Developer: Jose Rosado A class with some of the functions I used in FoxPro Example: Load "foxring.ring" mf = new frFunctions ? mf.frAbs(-45) ? mf.frAbs(10-30) ? mf.frAbs(30-10) ? mf.frTransform(" Ring is a good language ", "@! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") ? mf.frAllTrim(" Ring is a good language ", Null) Output: 45 20 20 RING IS A GOOD LANGUAGE Ring is a good language 6.13 Better Form Designer 1. Layout Control - Display the control name when loading forms. 2. Button Control - Display the button images written using relative path. 3. Table Control - Display the control name when loading forms. 4. Better behavior in “Bring to front” and “Send to back” operations. 5. New buttons are added to the toolbar (Duplicate, Bring to front, Send to back, Delete). 6. Using layouts in (Menubar designer, Window Flags window, Selecting Objects window). 6.12. FoxRing Library 77
Ring Documentation, Release 1.10 7. Better behavior for displaying the properties window when changing the selected objects. 8. New buttons are added to move and resize multiple selection of objects. 9. Window Properties - Add button to select the layout. 10. Opening forms and switching between files is faster. 11. Objects Order window. 12. Select Objects window. 13. When we change the control name, the name will be updated in layout objects. 6.14 Better Cards Game The Cards game is updated and we can play with the Computer 6.15 Better RingQt • The next classes are added to RingQt 1. QTabBar 2. QFile 3. QFileDevice 4. QStandardPaths 5. QDir 6. QQuickWidget 7. QQmlError 6.14. Better Cards Game 78
Ring Documentation, Release 1.10 8. QScrollBar • RingQt for Android is updated to support modern versions of Qt Tested using 1. Qt 5.5.1 2. Qt 5.9.5 3. Qt 5.11.0 • In RingQt for Android, The Ring Object File (ringo) will be executed directly from resources. 6.16 Better Code Generator For Extensions New Option: StaticMethods Starting from Ring 1.8 the code generator support the staticmethods option. So the code generator can know that the class doesn’t need an object to call the methods. Example: <class> name: QStandardPaths para: void nonew staticmethods </class> QString displayName(QStandardPaths::StandardLocation type) QString findExecutable(QString executableName, QStringList paths)) 6.17 Better Ring Compiler and VM 1. Better loading for files in relative paths 2. Code Optimization for eval() function 3. Better Memory Pool 4. 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: 6.16. Better Code Generator For Extensions 79
Ring Documentation, Release 1.10 Start the test! Let us try having an error Line 1 Error (R24) : Using uninitialized variable : x in file Ring_EmbeddedCode End of test! 5. 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 6. Better code (faster) for the main loop, special loop for eval() function. 7. Better code (faster) for tracking C pointers to avoid using NULL pointers. 8. Better code (faster) for getting the self object using braces. 6.18 Notes to extensions creators If you have created new extensions for Ring in the C/C++ languages. You have to rebuild your extension (Generate the DLL file again using Ring 1.8 header files) before usage with Ring 1.8 Because we changed the internal structure of the VM, but no changes to the code are required. just rebuild. 6.18. Notes to extensions creators 80
CHAPTER SEVEN WHAT IS NEW IN RING 1.7? In this chapter we will learn about the changes and new features in Ring 1.7 release. 7.1 List of changes and new features Ring 1.7 comes with many new features! • New Command: Load Package • ringvm_see() and ringvm_give() functions • ring_state_new() and ring_state_mainfile() functions • Better Trace Library • Better Ring Notepad • Better RingQt • Better Ring2EXE • Better RingZip • Better Documentation • Better Ring VM • RingLibuv Extension 7.2 New Command: 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 Now we have the “Load Package” command too 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 81
Ring Documentation, Release 1.10 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 7.3 ringvm_see() and ringvm_give() functions Using the ringvm_see() function we can redefine the behavior of the See command Also we can use ring_see() to have the original behavior Example: see "Hello world" + nl see 123 + nl see ["one","two","three"] see new point {x=10 y=20 z=30} func ringvm_see t ring_see("We want to print: ") ring_See(t) class point x y z Output: We want to print: Hello world We want to print: 123 We want to print: one two three We want to print: x: 10.000000 y: 20.000000 z: 30.000000 Using the ringvm_give() function we can redefine the behavior of the Give command Also we can use ring_give() to have the original behavior 7.3. ringvm_see() and ringvm_give() functions 82
Ring Documentation, Release 1.10 Example: see "Name: " give name see "Hello " + name func ringvm_give see "Mahmoud" + nl return "Mahmoud" Output: Name: Mahmoud Hello Mahmoud 7.4 ring_state_new() and ring_state_mainfile() functions 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. 7.5 Better Trace Library The Trace library is updated, In the Debugger at break points we have now the “callstack” command This command will print the functions call stack. Example: load "tracelib.ring" func main ? "Hello from main!" test1() func test1 ? "Hello from test1!" test2() func test2 ? "Hello from test2!" test3() func test3 ? "Hello from test3!" breakpoint() 7.4. ring_state_new() and ring_state_mainfile() functions 83
Ring Documentation, Release 1.10 7.6 Better Ring Notepad Ring Notepad comes with the next updates 1. Support *.cf extension 2. Using Hash function (SHA256) for better “Save Changes?” message 3. Ring Notepad - X Button - Ask for saving changes? 7.7 Better RingQt The next classes are added to RingQt 1. QStackedWidget 2. QCalendarWidget 3. QOpenGLFunctions 4. QOpenGLContext 5. QSurfaceFormat 6. QOpenGLWidget 7. QOpenGLVersionProfile 8. QOpenGLFunctions_3_2_Core 9. QVector2D 10. QVector3D 11. QVector4D 7.6. Better Ring Notepad 84
Ring Documentation, Release 1.10 12. QQuaternion 13. QMatrix4x4 14. QOpenGLPaintDevice 15. QPaintDevice 16. QOpenGLTimerQuery 17. QOpenGLDebugLogger 18. QOpenGLFramebufferObject 19. QOpenGLVertexArrayObject 20. QOpenGLBuffer 21. QOpenGLShaderProgram 22. QOpenGLShader 23. QOpenGLTexture 7.8 Better Ring2EXE Ring2EXE is updated to works as expected when we don’t have a C/C++ compiler Where we can distribute applications and get (exe file and ringo file) in this case. 7.9 Better RingZip The library is updated to support extracting files contains sub folders! 7.10 Better Documentation 1. RingQt Classes Chapter - The classes are sorted. 7.11 Better Ring VM 1. Better Error Message 2. List2Str() function support lists contains numbers 3. Correct support for numbers contains _ as separator 4. Creating lists without variables (statement –> Expression –> List) 5. IsNULL() - Not case sensitive - treat Null and null like NULL 6. Support adding the Self object to an attribute in this object 7. Using ‘:’ operator then keyword will create lower case literal 8. Printing objects - respect decimals() function 9. When literal is not closed - determine the start of the literal 7.8. Better Ring2EXE 85
Ring Documentation, Release 1.10 10. Better message when printing objects contains lists 11. VarPtr() - Support getting a pointer to variables in the local scope 12. replace performance instructions with normal instructions when creating new threads 7.12 RingLibuv Extension Ring 1.7 comes with the RingLibuv extension Libuv is a multi-platform support library with a focus on asynchronous I/O. Example (Events Loop): load "libuv.ring" counter = 0 idler = NULL func main idler = new_uv_idle_t() uv_idle_init(uv_default_loop(), idler) uv_idle_start(idler, "wait()") ? "Idling..." uv_run(uv_default_loop(), UV_RUN_DEFAULT); uv_loop_close(uv_default_loop()); destroy_uv_idle_t(idler) func wait counter++ if counter >= 100000 uv_idle_stop(idler) ok Output: Idling... Example (Server): load "libuv.ring" load "objectslib.ring" ? "Testing RingLibuv - Server Side - Using Classes" open_object(:MyServer) class MyServer from ObjectControllerParent DEFAULT_PORT = 13370 DEFAULT_BACKLOG = 1024 addr = new_sockaddr_in() server = NULL client = NULL myloop = NULL func start myloop = uv_default_loop() 7.12. RingLibuv Extension 86
Ring Documentation, Release 1.10 server = new_uv_tcp_t() uv_tcp_init(myloop, server) uv_ip4_addr("127.0.0.1", DEFAULT_PORT, addr) uv_tcp_bind(server, addr, 0) r = uv_listen(server, DEFAULT_BACKLOG, Method(:newconnection) ) if r ? "Listen error " + uv_strerror(r) return 1 ok uv_run(myloop, UV_RUN_DEFAULT) destroy_uv_tcp_t(server) destroy_uv_sockaddr_in(addr) func newconnection ? "New Connection" aPara = uv_Eventpara(server,:connect) nStatus = aPara[2] if nStatus < 0 ? "New connection error : " + nStatus return ok client = new_uv_tcp_t() uv_tcp_init(myloop, client) if uv_accept(server, client) = 0 uv_read_start(client, uv_myalloccallback(), Method(:echo_read)) ok func echo_read aPara = uv_Eventpara(client,:read) nRead = aPara[2] buf = aPara[3] if nRead > 0 req = new_uv_write_t() wrbuf = uv_buf_init(get_uv_buf_t_base(buf), nread) uv_write(req, client, wrbuf, 1, Method(:echo_write)) ? uv_buf2str(wrbuf) message = "message from the server to the client" buf = new_uv_buf_t() set_uv_buf_t_len(buf,len(message)) set_uv_buf_t_base(buf,varptr("message","char *")) uv_write(req, client, buf, 1, Method(:echo_write)) ok func echo_write aPara = uv_Eventpara(client,:read) req = aPara[1] Output: When we run the client, We will see the message “New Connection” Then the message “hello from the client” Testing RingLibuv - Server Side - Using Classes New Connection hello from the client Example (Using Threads): 7.12. RingLibuv Extension 87
Ring Documentation, Release 1.10 load "libuv.ring" load "objectslib.ring" ? "Testing RingLibuv - Threads - Using Classes" open_object(:MyThreads) class MyThreads from ObjectControllerParent func Start one_id = new_uv_thread_t() two_id = new_uv_thread_t() uv_thread_create(one_id, Method(:One)) uv_thread_create(two_id, Method(:Two)) uv_thread_join(one_id) uv_thread_join(two_id) destroy_uv_thread_t(one_id) destroy_uv_thread_t(two_id) func one ? "Message from the First Thread!" func Two ? "Message from the Second Thread!" Output: Testing RingLibuv - Threads - Using Classes Message from the First Thread! Message from the Second Thread! For more information about this extension (RingLibuv) check the chapter: Using RingLibuv 7.12. RingLibuv Extension 88
CHAPTER EIGHT WHAT IS NEW IN RING 1.6? In this chapter we will learn about the changes and new features in Ring 1.6 release. 8.1 List of changes and new features Ring 1.6 comes with many new features! • Employee Application • New Tool: Ring2EXE • Better Ring For Android • New Tool : Folder2qrc • Better Scripts for building Ring • RingConsoleColors Extension • RingMurmurHash Extension • Better Ring Notepad • Better RingQt • Better StdLib • Better RingVM • Better RingREPL • Using Tab instead of char(9) • Using CR as Carriage return • Using the ! operator as not • Using && and || operators • Using ? to print expression then new line 8.2 Employee Application The Employee application is added to ring/applications Developer: Ahmed Hassouna 89
Ring Documentation, Release 1.10 8.3 New Tool: Ring2EXE In 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 and Mobile devices Read the chapter “Distributing Ring Applications using Ring2EXE” for more information! 8.4 Better Ring For Android Ring For Android (using RingQt) is updated to use the Ring Object File ( *.ringo ) instead of using many source code files ( *.ring ) The next screen shot is an example of building the cards game for Android We are using cards.ringo instead of cards.ring If you have large project (many *.ring files) it will use only one *.ringo file. 8.3. New Tool: Ring2EXE 90
Ring Documentation, Release 1.10 To prepare Qt project to distribute RingQt application for Mobile use Ring2EXE Example ring2exe cards.ring -dist -mobileqt Example (2) ring2exe formdesigner.ring -dist -mobileqt 8.4. Better Ring For Android 91
Ring Documentation, Release 1.10 8.5 New Tool: 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! 8.6 Better Scripts for building Ring Ring 1.6 comes with better scripts for building Ring from source code. The updates are tested on 32bit and 64bit systems on Windows, Linux (Ubuntu,Fedora) and macOS. The scripts for Windows are updated to find the Visual C/C++ compiler based on your Visual Studio version. 8.7 RingConsoleColors Extension Using the RingConsoleColors extension we can easily change the colors used in our console applications For more information check the RingConsoleColors chapter in the documentation. 8.5. New Tool: Folder2qrc 92
Ring Documentation, Release 1.10 8.8 RingMurmurHash Extension Ring 1.6 comes with the RingMurmurHash extension! Developer: Hassan Ahmed Example: load "murmurhashlib.ring" key = "Ring Language" see murmurhash3_x86_32(key, 0, 0) + nl // Output: 1894444853 see murmurhash3_x86_32(key, 0, 1) + nl // Output: 70eaef35 For more information check the RingMurmurHash chapter in the documentation. 8.9 Better Ring Notepad Ring Notepad comes with the next updates 1. Automatic setting for the Main File when we Run the application (using the Main file buttons). 2. Main File - Automatic save before running. 3. When we run GUI application - don’t change the focus to the text box used for the input in the Output Window. 4. A button and option to run web applications For Windows users, Ring 1.6 comes with Apache Web server! We can run any web application from any folder directly without doing any configuration. 8.8. RingMurmurHash Extension 93
Ring Documentation, Release 1.10 5. Tools - Operating System - Terminal (Command Prompt) & Files Manager (Explorer). So we can quickly open the Command Prompt or the Explorer at the application folder. 8.9. Better Ring Notepad 94
Ring Documentation, Release 1.10 6. Support *.sh & *.bat extensions. 7. New Menu: Distribute 8.10 Better RingQt RingQt comes with the next updates 1. QAllEvents - getkeytext() Method 2. QSQLQuery - exec_2() Method 3. QDockWidget Events 4. AppFile() Function 5. IsMobile() Function 8.10. Better RingQt 95
Ring Documentation, Release 1.10 6. QRegion Class 7. QCoreApplication class 8.11 Better StdLib StdLib comes with the next updates 1. Factors() function is updated (Return the output instead of printing it) 2. Palindrome() function is updated (Return the output instead of printing it) 3. Using stdlibcore.ring we can use the StdLib functions (Without Classes) Also this is useful when developing standalone console applications Because using stdlib.ring (functions & classes) will load libraries like RingLibCurl, RingOpenSSL, etc. 4. New Functions • SystemSilent(cCommand) Function : Execute system commands without displaying the output. • OSCreateOpenFolder(cFolder) : Create folder then change the current folder to this new folder • OSCopyFolder(cParentFolder,cFolderNameToCopy) : Copy folder to the current directory • OSDeleteFolder(cFolder) : Delete Folder • OSCopyFile(cFileName) : Copy File to the current directory • OSDeleteFile(cFileName) : Delete File • OSRenameFile(cOldFileName,cNewFileName) : Rename file 8.12 Better RingVM RingVM comes with the next updates 1. Support using many getter methods in Expressions 2. Support using this & self in setter/getter/normal methods without calling setter/getter methods. 3. TempName() function is updated (Better Code) 4. ExeFileName() function is updated (Better Code) 5. Private Attributes - Support re-usage in the class region (After the keyword private) 6. Ring API : ring_scanner_runobjstring() 7. ring_state_setvar() function 8.13 Better RingREPL RingREPL comes with the next updates 1. RingREPL will get command line parameters to determine the style. 2. Setting RingREPL Style based on Ring Notepad Style. 8.11. Better StdLib 96
Ring Documentation, Release 1.10 8.14 Using Tab instead of char(9) The variable Tab is defined to be used instead of char(9) Example (1): see :one + nl + tab + :two + nl + tab + tab + :three Output: one two three You can change the variable to another value Example (2): tab = " " see :one + nl + tab + :two + nl + tab + tab + :three Output: one two three 8.15 Using CR as Carriage return The next example count from 1 to 10 in the same line during 10 seconds load "stdlibcore.ring" for x = 1 to 10 see x sleep(1) see cr next 8.16 Using the ! operator as not We have = and != in the Ring language But for the logical operators we have and, or & not Now we can use the ! operator as not Example: if ! false see "True!" + nl ok Output True! 8.17 Using && and || operators In Ring we have the next keywords for the logical operations 8.14. Using Tab instead of char(9) 97
Ring Documentation, Release 1.10 • and • or • not Now we have also the next operators • && • || • ! Example: if one() and two() see "Test1 - Fail" + nl else see "Test1 - Pass" + nl ok if two() or one() see "Test2 - Pass" + nl else see "Test2 - Fail" + nl ok if one() && two() see "Test3 - Fail" + nl else see "Test3 - Pass" + nl ok if two() || one() see "Test4 - Pass" + nl else see "Test4 - Fail" + nl ok func one return True func two return False Output: Test1 - Pass Test2 - Pass Test3 - Pass Test4 - Pass 8.18 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 8.18. Using ? to print expression then new line 98
Ring Documentation, Release 1.10 ? x next Output: Hello, World! 1 2 3 4 5 6 7 8 9 10 8.18. Using ? to print expression then new line 99
CHAPTER NINE WHAT IS NEW IN RING 1.5? In this chapter we will learn about the changes and new features in Ring 1.5 release. 9.1 List of changes and new features Ring 1.5 comes with many new features! • Video-Music-Player Application • Windows StartUp Manager Application • Calculator Application • Better Ring Notepad • Better StdLib • Better WebLib • Better RingQt • Better Objects Library • RingFreeGLUT Extension • RingOpenGL Extension • Better Code Generator for Extensions • Better Documentation Generator for Extensions • Ring VM - Tracing Functions • Trace Library and Interactive Debugger • More Syntax Flexibility • Type Hints Library • Better Quality 9.2 Video-Music-Player Application The Video-Music-Player application is added to the Applications folder. Screen Shot: 100
Ring Documentation, Release 1.10 9.3 Windows StartUp Manager Application The Windows StartUp Manager URL : https://github.com/ring-lang/WinStartupManager Screen Shot: 9.3. Windows StartUp Manager Application 101
Ring Documentation, Release 1.10 9.4 Calculator Application The Calculator application is added to the Applications folder. Screen Shot: 9.5 Better Ring Notepad 1. Ring Notepad is updated to include some new styles and the Main File ToolBar The idea of the Main File ToolBar is to determine the main file in the project When the project contains many source code files This way you 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: 9.4. Calculator Application 102
Ring Documentation, Release 1.10 9.5. Better Ring Notepad 103
Ring Documentation, Release 1.10 2. The output window is updated to display the new lines correctly and contains the “Clear” button. Screen Shot: (3) The Ring Notepad is updated to quickly open and switch between large files while preparing the functions/classes lists in the background. Screen Shot: 9.5. Better Ring Notepad 104
Ring Documentation, Release 1.10 9.6 Better StdLib New Functions • Print2Str() • ListAllFiles() • SystemCmd() 1. The Print2Str() is a new function added to the StdLib Example: load "stdlib.ring" world = "World!" mystring = print2str("Hello, #{world} nIn Year n#{2000+17} n") see mystring + nl Output: Hello, World! In Year 2017 2. The ListAllFiles() is a new function added to the StdLib Using this function we can quickly do a process on a group of files in a folder and it’s sub folders. Example: load "stdlib.ring" aList = ListAllFiles("c:/ring/ringlibs","ring") # *.ring only 9.6. Better StdLib 105
Ring Documentation, Release 1.10 aList = sort(aList) see aList Example: load "stdlib.ring" see listallfiles("b:/ring/ringlibs/weblib","") # All Files 3. The SystemCmd() is a new function added to the StdLib The function will execute a system command like the System() function but will return the output in a string. Example: cYou = SystemCmd("whoami") See "SystemCmd: whoami ====="+ nl + cYou +nl Output: SystemCmd: whoami ===== desktop-umbertoumberto 9.7 Better WebLib The WebLib is updated to include the 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 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) 9.7. Better WebLib 106
Ring Documentation, Release 1.10 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()) Using this feature 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 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 9.7. Better WebLib 107
Ring Documentation, Release 1.10 { 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()) func PrintEvent printer1 = new qPrinter(0) { setoutputformat(1) setoutputfilename("report.pdf") } oView { web.print(printer1) web.show() } system ("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: 9.7. Better WebLib 108
Ring Documentation, Release 1.10 9.8 Better RingQt New classes added to RingQt : • QStringRef • QMutex • QMutexLocker • QBuffer • QBluetoothAddress • QBluetoothDeviceDiscoveryAgent • QBluetoothDeviceInfo • QBluetoothHostInfo • QBluetoothLocalDevice • QBluetoothServer • QBluetoothServiceDiscoveryAgent • QBluetoothServiceInfo • QBluetoothSocket • QBluetoothTransferManager • QBluetoothTransferReply • QBluetoothTransferRequest • QBluetoothUuid 9.8. Better RingQt 109
Ring Documentation, Release 1.10 Example: ### Submits your car VIN - Vehicle Id Number - to the Web Site - vpic.nhtsa.dot.gov - ### Parses XML data returned ### Prints out the car info result load "libcurl.ring" load "guilib.ring" load "stdlib.ring" curl = curl_easy_init() # request = "3G1JC5248YS251015?format=xml" ### VIN - Chevrolet request = "3GYFK62847G247323?format=xml" ### VIN - Cadillac call_type = "decodevinvalues/" url = "https://vpic.nhtsa.dot.gov/api/vehicles/" url_request = url + call_type + request See "URL Request: "+ url_request +nl curl_easy_setopt(curl, curlopt_url, url_request) response = curl_easy_perform_silent(curl); See nl +"Response Raw: "+ response +nl +nl curl_easy_cleanup(curl) xml = new qxmlstreamreader() xml.adddata_2(response) x = new qstringref() while not xml.atend() if xml.error() see xml.errorstring() see nl exit loop ok x = xml.text() if not x.length() = 0 see "Length: " see x.length() +" --- " see "Value: " see x.tostring() see nl ok xml.readnext() end get x ###------------------------------------------ ### Results # # ==>Value: 115 # ==>Value: Results returned successfully # ==>Value: VIN(s): 3G1JC5248YS251015 # ==>Value: 3G1JC5248YS251015 # ==>Value: Sedan/Saloon # ==>Value: 4 # ==>Value: 2200.0 9.8. Better RingQt 110
Ring Documentation, Release 1.10 # ==>Value: 134.25223700841 # ==>Value: 2.2 # ==>Value: 4 # ==>Value: LN2 # ==>Value: CHEVROLET # ==>Value: GENERAL MOTORS LLC # ==>Value: Cavalier # ==>Value: 2000 # ==>Value: Ramos Arzipe # ==>Value: PASSENGER CAR # ==>Value: 4 # ==>Value: In-Line # ==>Value: 1st Row (Driver & Passenger) # ==>Value: Sequential Fuel Injection (SFI) # ==>Value: Mexico # ==>Value: NA # ==>Value: Manual # ==>Value: Body Type: Sedan, 4-6 Window, Notchback (GM codes: 19, 69) # ==>Value: Name Plate: Chevrolet, Pontiac # ==>Value: 0 - VIN decoded clean. Check Digit (9th position) is correct # ==>Value: LAN # ==>Value: 984 # ###----------------------------------------- 9.9 Better Objects Library The function Open_WindowInPackages() is added to the Objects library. The Open_WindowInPackages() function is the same as Open_Window() but takes an extra list that determine the packages to import before opening the window. Syntax: Open_WindowInPackages(cClassName,aPackagesList) Example: The next example from the Form Designer source code, Open the Window Flags window using the open_windowInPackages() function. We determine the class name “WindowFlagsController” and the packages name. The Window Flags window uses the FormDesigner and System.GUI packages. open_windowInPackages(:WindowFlagsController,[ "formdesigner", "System.GUI" ]) 9.10 RingFreeGLUT Extension Ring 1.5 comes with RingFreeGLUT extension to support the FreeGLUT library Example: 9.9. Better Objects Library 111
Ring Documentation, Release 1.10 /* This sample is based on C Tutorials from : http://www.lighthouse3d.com/tutorials/glut-tutorial/ */ 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 9.10. RingFreeGLUT Extension 112
Ring Documentation, Release 1.10 C_INT_GLUT_BITMAP_HELVETICA_12 = 12 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) 9.10. RingFreeGLUT Extension 113
Ring Documentation, Release 1.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 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) func computePos deltaMove 9.10. RingFreeGLUT Extension 114
Ring Documentation, Release 1.10 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() glPushMatrix() glLoadIdentity() 9.10. RingFreeGLUT Extension 115
Ring Documentation, Release 1.10 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 // ----------------------------------- // MOUSE // ----------------------------------- func mouseMove 9.10. RingFreeGLUT Extension 116
Ring Documentation, Release 1.10 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 // all actions are for submenus func processFillMenu 9.10. RingFreeGLUT Extension 117
Ring Documentation, Release 1.10 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 blue = 0.5 off func createPopupMenus 9.10. RingFreeGLUT Extension 118
Ring Documentation, Release 1.10 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) glutIgnoreKeyRepeat(1) glutKeyboardFunc(:processNormalKeys) glutSpecialFunc(:pressKey) glutSpecialUpFunc(:releaseKey) // here are the two new functions glutMouseFunc(:mouseButton) 9.10. RingFreeGLUT Extension 119
Ring Documentation, Release 1.10 glutMotionFunc(:mouseMove) // OpenGL init glEnable(GL_DEPTH_TEST) glEnable(GL_CULL_FACE) // init Menus createPopupMenus() // enter GLUT event processing cycle glutMainLoop() Screen Shots: 9.10. RingFreeGLUT Extension 120
Ring Documentation, Release 1.10 9.11 RingOpenGL Extension Ring 1.5 comes with RingOpenGL and 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 • OpenGL 4.4 • OpenGL 4.5 • OpenGL 4.6 Example: /* This sample is based on C Tutorials from : http://www.wikihow.com/Make-a-Cube-in-OpenGL */ 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 9.11. RingOpenGL Extension 121
Ring Documentation, Release 1.10 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 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 ) 9.11. RingOpenGL Extension 122
Ring Documentation, Release 1.10 glVertex3f( -0.5, -0.5, -0.5 ) glEnd() glFlush() glutSwapBuffers() // ---------------------------------------------------------- // specialKeys() Callback Function // ---------------------------------------------------------- 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) 9.11. RingOpenGL Extension 123
Ring Documentation, Release 1.10 // Pass control to GLUT for events glutMainLoop() // Return to OS Screen Shot: 9.12 Better Code Generator for Extensions The Code Generator is updated to support <constant> type, So we can have constants other than numbers, for example : Strings and Pointers. When we have pointers we can determine the pointer type. To use this feature, before <constant> and </constant> we can use $nDefaultConstantType = C_CONSTANT_TYPE_POINTER $cDefaultConstantPointerType = "void *" The next example from the RingFreeGLUT extension <runcode> $nDefaultConstantType = C_CONSTANT_TYPE_POINTER $cDefaultConstantPointerType = "void" </runcode> <constant> GLUT_STROKE_ROMAN GLUT_STROKE_MONO_ROMAN GLUT_BITMAP_9_BY_15 GLUT_BITMAP_8_BY_13 GLUT_BITMAP_TIMES_ROMAN_10 GLUT_BITMAP_TIMES_ROMAN_24 GLUT_BITMAP_HELVETICA_10 GLUT_BITMAP_HELVETICA_12 9.12. Better Code Generator for Extensions 124
Ring Documentation, Release 1.10 GLUT_BITMAP_HELVETICA_18 </constant> 9.13 Better Documentation Generator for Extensions The documentation generator for extensions is updated to generate a list of constants in the generated documentation The previous versions provides the functions prototype only, Now we have the list of constants too. 9.14 Ring VM - Tracing Functions In Ring 1.5 the next functions are added to Ring VM • RingVM_SetTrace(cCode) • RingVM_TraceData() –> aDataList • RingVM_TraceEvent() –> nTraceEvent • RingVM_TraceFunc() –> cCode • RingVM_ScopesCount() –> nScopes • RingVM_EvalInScope(nScope,cCode) • RingVM_PassError() • RingVM_HideErrorMsg(lStatus) • RingVM_CallFunc(cFuncName) Example: load "tracelib.ring" ringvm_settrace("mytrace()") see "Hello, world!" + nl see "Welcome" + nl see "How are you?" +nl mytest() new myclass { mymethod() } func mytest see "Message from mytest" + nl func mytrace see "====== The Trace function is Active ======" + nl + "Trace Function Name : " + ringvm_TraceFunc() + nl + "Trace Event : " switch ringvm_TraceEvent() on TRACEEVENT_NEWLINE see "New Line" on TRACEEVENT_NEWFUNC see "New Function" on TRACEEVENT_RETURN see "Return" on TRACEEVENT_ERROR see "Error" on TRACEEVENT_BEFORECFUNC see "Before C Function" on TRACEEVENT_AFTERCFUNC see "After C Function" off 9.13. Better Documentation Generator for Extensions 125
Ring Documentation, Release 1.10 see nl + "Line Number : " + ringvm_tracedata()[TRACEDATA_LINENUMBER] + nl + "File Name : " + ringvm_tracedata()[TRACEDATA_FILENAME] + nl + "Function Name : " + ringvm_tracedata()[TRACEDATA_FUNCNAME] + nl + "Method or Function : " if ringvm_tracedata()[TRACEDATA_METHODORFUNC] = TRACEDATA_METHODORFUNC_METHOD see "Method" else if ringvm_tracedata()[TRACEDATA_FUNCNAME] = NULL see "Command" else see "Function" ok ok see nl + Copy("=",42) + nl class myclass func mymethod see "Message from mymethod" + nl Output: ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : After C Function Line Number : 3 File Name : test1.ring Function Name : ringvm_settrace Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 5 File Name : test1.ring Function Name : Method or Function : Command ========================================== Hello, world! ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 6 File Name : test1.ring Function Name : Method or Function : Command ========================================== Welcome ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 7 File Name : test1.ring Function Name : Method or Function : Command ========================================== How are you? 9.14. Ring VM - Tracing Functions 126
Ring Documentation, Release 1.10 ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 8 File Name : test1.ring Function Name : Method or Function : Command ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Function Line Number : 8 File Name : test1.ring Function Name : mytest Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 12 File Name : test1.ring Function Name : mytest Method or Function : Function ========================================== Message from mytest ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 14 File Name : test1.ring Function Name : mytest Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : Return Line Number : 8 File Name : test1.ring Function Name : Method or Function : Command ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 9 File Name : test1.ring Function Name : Method or Function : Command ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 43 File Name : test1.ring Function Name : Method or Function : Command ========================================== ====== The Trace function is Active ====== 9.14. Ring VM - Tracing Functions 127
Ring Documentation, Release 1.10 Trace Function Name : mytrace() Trace Event : Before C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : After C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Function Line Number : 9 File Name : test1.ring Function Name : mymethod Method or Function : Method ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 44 File Name : test1.ring Function Name : mymethod Method or Function : Method ========================================== Message from mymethod ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : Return Line Number : 9 File Name : test1.ring Function Name : Method or Function : Command ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : Before C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : After C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() 9.14. Ring VM - Tracing Functions 128
Ring Documentation, Release 1.10 Trace Event : Before C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : After C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 11 File Name : test1.ring Function Name : Method or Function : Command ========================================== 9.15 Trace Library and Interactive Debugger Ring 1.5 comes with the Trace Library and the Interactive Debugger Using this library we can trace events, execute programs line by line, open the Interactive Debugger when an error happens or at breakpoints. Example: 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! 9.15. Trace Library and Interactive Debugger 129
Ring Documentation, Release 1.10 We can print the variables values We can change the variables values then continue execution We can run the Interactive Debugger in the Output Window 9.15. Trace Library and Interactive Debugger 130
Ring Documentation, Release 1.10 9.16 More Syntax Flexibility • Using braces { } in Packages/Classes/Functions Example: load "stdlib.ring" import mypackage new myclass { myfunc() } package mypackage { class myclass { func myfunc { print("Hello, World!n") } } } • Using ‘end’ keyword after Packages/Classes/Functions Example: import mypackage new myclass { myfunc() } 9.16. More Syntax Flexibility 131
Ring Documentation, Release 1.10 package mypackage class myclass def myfunc put "Hello, World!" end end end • Using ‘endpackage’/’endclass’/’endfunc’ keywords after Packages/Classes/Functions Example: import mypackage new myclass { myfunc() } package mypackage class myclass func myfunc see "welcome" + nl endfunc endclass endpackage 9.17 Type Hints Library Ring 1.5 comes with the Type Hints library 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 Example: 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 ; } The library is very powerful and support the User types (Classes) automatically! Example: load "typehints.ring" import mypackage test() { main([:one,:two,:three]) } 9.17. Type Hints Library 132
Ring Documentation, Release 1.10 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 } } } 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 ; } 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). Note: Ring is a dynamic language, No type checking will be done by the compiler. 9.18 Better Quality Based on Ring usage every day in practical projects Ring 1.5 is more stable and more productive! We are adding features based on clear vision and practical needs. Also the documentation is better. 9.19 What is new in Ring 1.5.1? • Better Documentation 9.18. Better Quality 133
Ring Documentation, Release 1.10 • StdLib - Factorial() function update • RingVM - Better code for clearing the stack in the Class Region. • Sample : 3D Cube (OpenGL) + Texture Image using GameLib (RingAllegro) Source Code: load "gamelib.ring" load "opengl21lib.ring" 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) 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) 9.19. What is new in Ring 1.5.1? 134
Ring Documentation, Release 1.10 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) 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() xrot += 0.3 yrot += 0.2 zrot += 0.4 class GraphicsAppBase display event_queue ev timeout timer redraw = true FPS = 60 SCREEN_W = 800 SCREEN_H = 600 KEY_UP = 1 9.19. What is new in Ring 1.5.1? 135
Ring Documentation, Release 1.10 KEY_DOWN = 2 KEY_LEFT = 3 KEY_RIGHT = 4 Key = [false,false,false,false] TITLE = "Graphics Application" func start SetUp() loadResources() eventsLoop() destroy() func setup al_init() 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_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 9.19. What is new in Ring 1.5.1? 136
Ring Documentation, Release 1.10 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) func loadresources func drawScene func destroyResources Screen Shot: 9.19. What is new in Ring 1.5.1? 137
Ring Documentation, Release 1.10 9.20 What is new in Ring 1.5.2? • Documentation - Chapter “Applications developed in little hours” is updated • Ring Notepad - Display programs output in the output window on all platforms • Form Designer - Help Menu - Open CHM/PDF files without displaying the console window • Form Designer - Better response to Resize/Move Events when moving the Mouse quickly • Form Designer - New/Open/Save As, will open the Controller class in Ring Notepad • Form Designer - Added “Close Form” option to the file menu • Ring Notepad - Run, will save the current file (Also the opened Form) automatically • GetQuotesHistory Application - Updated to work on MacOS X and Qt 5.2 • Calculator Application - Updated to include more features! • RingVM - Classification for Environment Errors (Check Chapter : Language Reference) • RingQt - New methods added to QAllEvents for faster Events execution • RingQt - Fusion Black Style - Better colors for disabled controls • Scripts - For building Ring on Fedora Linux (Check Chapter : Building From Source Code) Screen Shot: 9.20. What is new in Ring 1.5.2? 138
Ring Documentation, Release 1.10 9.21 What is new in Ring 1.5.3? • Form Designer : Close Action will notify Ring Notepad to be able to open the Form again • Form Designer : Save Action will open the controller class in Ring Notepad • Form Designer : Keep current control selected when selecting many controls using CTRL Key • Form Designer : Nice form back color when used in Ring Notepad (Style: Modern Black) • RingOpenSSL : Updated to support newer versions like OpenSSL 1.1 • Building Scripts : Updated to work on Fedora 26 (64bit) • OpenGL : New Sample - Many Cubes (samples/3D/manycubes) Screen Shot: 9.21. What is new in Ring 1.5.3? 139
Ring Documentation, Release 1.10 • RingQt : Add QDateTime Class • RingQt : New methods added to QMenu and QCursor Classes Example: load "guilib.ring" new qApp { win = new qwidget() { setwindowtitle("Context Menu") resize(400,400) myfilter = new qAllEvents(win) { setContextmenuEvent("mymenu()") } installeventfilter(myfilter) show() } exec() } func mymenu new qMenu(win) { 9.21. What is new in Ring 1.5.3? 140
Ring Documentation, Release 1.10 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()) } • Compiler : Support using _ in numbers Example: x = 1_000_000 see type(x)+nl see x+1+nl Output: NUMBER 100000001 • Compiler : Support using f after numbers Example: x = 19.99f see type(x) + nl Output: NUMBER • Google API Shortener Application Screen Shots: 9.21. What is new in Ring 1.5.3? 141
Ring Documentation, Release 1.10 • TicTacToe 3D Game Screen Shot: 9.22 What is new in Ring 1.5.4? • CalmoSoft Fifteen Puzzle Game 3D • Ring Notepad - New Styles 9.22. What is new in Ring 1.5.4? 142
Ring Documentation, Release 1.10 • Ring Notepad - Better Toolbar Style • Ring Notepad - View Modes • Ring Notepad - QPlainTextEdit - don’t set back color for the scroll bars • Ring Notepad - Style Fusion (White) - use Silver color for comments • Ring Notepad - Tab and Shift-Tab - Indent multiple lines • Form Designer - Better Toolbar Style • Form Designer - Nice backcolor for Window Flags and Menubar Designer • Form Designer - Default back color for controls • RingQt - Added grab() and windowHandle() methods to QWidget class • RingQt - Added new methods to QPixmap Class • RingQt - Added Classes :- – QScreen – QWindow – QGuiApplication – QTextBrowser • Code Generator for Extensions - Nonew Option - Support Parent Class • Ring VM - Internal Implementation - Pass state to Strings and Lists objects • Ring VM - Garbage Collector - Memory Pool for Small Objects • Ring VM - Better code for Saving/Restoring the State 9.22. What is new in Ring 1.5.4? 143
CHAPTER TEN WHAT IS NEW IN RING 1.4? In this chapter we will learn about the changes and new features in Ring 1.4 release. 10.1 List of changes and new features Ring 1.4 comes with many new features • Change: Basic Extensions are separated from RingVM • The Natural Library • New Style is added to Ring Notepad • RingREPL • Convert between Numbers and Bytes • Better StdLib • Better WebLib • Better RingQt • Qt Class Convertor 10.2 Change: Basic Extensions are separated from RingVM In Ring 1.4 the next libraries are separated from RingVM • RingODBC • RingMySQL • RingSQLite • RingOpenSSL • RingInternet To use these libraries, Use the Load command. load "odbclib.ring" # use ODBC Functions load "mysqllib.ring" # use MySQL Functions 144
Ring Documentation, Release 1.10 load "sqlitelib.ring" # use SQLite Functions load "openssllib.ring" # use OpenSSL Functions ( Hash and Security functions) load "internetlib.ring" # use Internet Functions ( Download() and SendEmail() ) If you will use all of these libraries, You can just use stdlib.ring And the stdlib.ring will load odbclib.ring, mysqllib.ring, sqlitelib.ring, opensslib.ring and internetlib.ring files. load "stdlib.ring" 10.3 The Natural Library Ring 1.4 comes with the Natural Library to quickly define a language that contains a group of commands. 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. 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! 10.3. The Natural Library 145
Ring Documentation, Release 1.10 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) 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 10.3. The Natural Library 146
Ring Documentation, Release 1.10 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) } ]) 10.4 New Style is added to Ring Notepad In Ring Notepad - From View - Styles - Select the (Modern) Style Screen Shot: 10.4. New Style is added to Ring Notepad 147
Ring Documentation, Release 1.10 10.5 RingREPL In the application folder, You will find RingREPL (Read-Eval-Print-Loop) Also you can run it from Ring Notepad (Menubar - Tools) Screen Shot: 10.6 Convert between Numbers and Bytes Ring 1.4 comes with the next functions to convert between Numbers and Bytes. • Int2Bytes() • Float2Bytes() • Double2Bytes() • Bytes2Int() • Bytes2Float() 10.5. RingREPL 148
Ring Documentation, Release 1.10 • Bytes2Double() Example: 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 10.7 Better StdLib The StdLib is updated to include the next functions • FSize() The print() function is updated to accept local variables. load "stdlib.ring" func main print("Enter your name : ") ; Name = getString() ; print( "Hello : #{Name} ") ; return ; 10.8 Better WebLib The web library is updated • Provide better error message 1. Error (WebLib-1) : REQUEST_METHOD is empty ! - Run this script from the browser 2. Error (DataLib-1) : Can’t connect to the database server! • Better Template() function - can accept NULL instead of object as the second paramter. html(template("main.rhtml",NULL)) • The Form Class is updated to support the “target” attribute. BootStrapWebPage() { Title = "The Ring Programming Language" html(template("main.rhtml",NULL)) 10.7. Better StdLib 149
Ring Documentation, Release 1.10 div { classname = :container div { id = "div3" color = "black" backgroundcolor = "white" width = "100%" form { method = "POST" Action = website Target = "codeoutput" input { type="hidden" name="page" value=1 } Table { style = stylewidth("100%") + stylegradient(3) TR { TD { align="center" WIDTH="10%" text("Code :") } TD { html(` <textarea name = "cCode" rows="5" style="width : 100%; "> See "Hello, World!" + nl </textarea>`) } } } Input { type = "submit" classname="btn btn-primary btn-block" value = "Execute" } Table { style = stylewidth("100%") + stylegradient(34) TR { TD { align="center" WIDTH="10%" text("Output :") } TD { html(` <iframe name="codeoutput" width="100%" style="background-color:white;"> </iframe>`) } } } 10.8. Better WebLib 150
Ring Documentation, Release 1.10 } } } html(template("footer.rhtml",NULL)) } 10.9 Better RingQt The next functions are added to RingQt • SetDialogIcon(cIconFile) • MsgInfo(cTitle,cMessage) • ConfirmMsg(cTitle,cMessage) • InputBox(cTitle,cMessage) • InputBoxInt(cTitle,cMessage) • InputBoxNum(cTitle,cMessage) • InputBoxPass(cTitle,cMessage) The next classes are added to RingQt • QToolButton • QSerialPort • QSerialPortInfo 10.10 Qt Class Convertor Ring 1.4 comes with a simple tool that help in porting Qt classes to RingQt. You will find it in ring/samples/tools/QtClassConverter Online : https://github.com/ring-lang/ring/tree/master/samples/tools/QtClassConverter Screen Shot: 10.9. Better RingQt 151
Ring Documentation, Release 1.10 10.11 What is new in Ring 1.4.1? Ring 1.4.1 comes with the next changes • Better Scripts for Building from Source Code • Better Colors for the Modern Style in Ring Notepad • Better StdLib • Better RingQt • New Sample : Sixteen Puzzle The scripts are updated for building from source code. Tested using Windows, Ubuntu Linux, Linux Mint and MacOS X. Screen Shot: 10.11. What is new in Ring 1.4.1? 152
Ring Documentation, Release 1.10 In Ring Notepad - the (Modern) Style colors are updated Screen Shot: The StdLib is updated to include the next functions • TrimLeft() • TrimRight() • TrimAll() • EpochTime() 10.11. What is new in Ring 1.4.1? 153
Ring Documentation, Release 1.10 The next functions are updated to display the dialogs on the top of other windows. • SetDialogIcon(cIconFile) • MsgInfo(cTitle,cMessage) • ConfirmMsg(cTitle,cMessage) • InputBox(cTitle,cMessage) • InputBoxInt(cTitle,cMessage) • InputBoxNum(cTitle,cMessage) • InputBoxPass(cTitle,cMessage) The Sixteen Puzzle is added to the Applications folder. Screen Shot: 10.11. What is new in Ring 1.4.1? 154
Ring Documentation, Release 1.10 10.11. What is new in Ring 1.4.1? 155
CHAPTER ELEVEN WHAT IS NEW IN RING 1.3? In this chapter we will learn about the changes and new features in Ring 1.3 release. 11.1 List of changes and new features Ring 1.3 comes with many new features • Better RingQt • Better Ring Notepad • Ring mode for Emacs Editor • Better StdLib • Better Loop/Exit Command • New Functions • Return Self by Reference • Using ‘<’ and ‘:’ operators as ‘from’ keyword • Embedding Ring in Ring without sharing the State • RingZip Library • Form Designer 11.2 Better RingQt (1) Another version of QPixMap class is added (QPixMap2) which takes (int width,int height) during object init. Example: Load "guilib.ring" New qapp { win1 = new qwidget() { setwindowtitle("Drawing using QPixMap") setgeometry(100,100,500,500) label1 = new qlabel(win1) { setgeometry(10,10,400,400) settext("") 156
Ring Documentation, Release 1.10 } imageStock = new qlabel(win1) { image = new qPixMap2(200,200) color = new qcolor() { setrgb(255,255,255,255) } pen = new qpen() { setcolor(color) setwidth(10) } new qpainter() { begin(image) setpen(pen) drawline(0,0,200,200) drawline(200,0,0,200) endpaint() } setpixmap(image) } show() } exec() } Screen Shot: 11.2. Better RingQt 157
Ring Documentation, Release 1.10 2. The Objects Library is updated to include the next functions • Last_WindowID() • Open_WindowNoShow() • Open_WindowAndLink() Also the class name (WindowViewBase) is changed to (WindowsViewParent). In The next code for example the Open_WindowAndLink() will create an object from the SecondWindowController Class Then will add the Method SecondWindow() to the FirstWindowController Class Also will add the Method FirstWindow() to the SecondWindowController Class So the SendMessage() method in FirstWindowController class can use the SecondWindow() method to access the object. class firstwindowController from windowsControllerParent oView = new firstwindowView func OpenSecondWindow Open_WindowAndLink(:SecondWindowController,self) 11.2. Better RingQt 158
Ring Documentation, Release 1.10 func SendMessage if IsSecondWindow() SecondWindow().setMessage("Message from the first window") ok func setMessage cMessage oView.Label1.setText(cMessage) 3. The next classes are added to RingQt • QPixMap2 • QScrollArea • QSplitter • QCompleter • QCompleter2 • QCompleter3 • QProcess • QMdiArea • QMdiSubWindow • QCursor • QListView • QDesktopServices 4. Many constants are defined in qt.rh (loaded by guilib.ring) 5. 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/applications/formdesigner/tests/indexstart/indexstartView.ring 11.2. Better RingQt 159
Ring Documentation, Release 1.10 2. https://github.com/ring-lang/ring/blob/master/applications/formdesigner/tests/indexstart/indexstartController.ring 11.3 Better Ring Notepad 1. Using QPlainTextEdit instead of QTextEdit 2. Displaying the line number for each line in the source code file. Screen Shot: 3. Auto-Complete for Ring functions names, classes and words in the opened file. 11.3. Better Ring Notepad 160
Ring Documentation, Release 1.10 4. Functions and Methods List 11.3. Better Ring Notepad 161
Ring Documentation, Release 1.10 5. Output Window 6. Classes List 11.3. Better Ring Notepad 162
Ring Documentation, Release 1.10 7. Change the Current Style 11.4 Ring mode for Emacs Editor Ring 1.3 comes with Ring mode for Emacs Editor Screen Shot: 11.4. Ring mode for Emacs Editor 163
Ring Documentation, Release 1.10 11.5 Better StdLib The StdLib is updated to include the next functions • SplitMany() • JustFilePath() • JustFileName() 11.6 Better Loop|Exit Command The Loop|Exit command is updated to accept Expressions after the command (not only numbers). The syntax: Loop|Exit [Number] Changed to Loop|Exit [Expression] Example XLoop = 2 # The outer loop YLoop = 1 # The first inner loop for x = 1 to 10 for y = 1 to 10 see "x=" + x + " y=" + y + nl if x = 3 and y = 5 exit XLoop ok 11.5. Better StdLib 164
Ring Documentation, Release 1.10 next next 11.7 New Functions • PackageName() function • 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 11.8 Return Self by Reference In this release, using Return Self in class methods will return the object by reference. Example: mylist = [new mytest() { see self x = 20 see self }] see mylist class mytest x = 15 func init return self # Return by reference Output x: 15.000000 x: 20.000000 x: 20.000000 11.7. New Functions 165
Ring Documentation, Release 1.10 11.9 Using ‘<’ and ‘:’ operators as ‘from’ keyword In this release of the Ring language we can use the ‘<’ and ‘:’ operators as the ‘from’ keyword Syntax (1): class Cat from Animal Syntax (2): class Cat < Animal Syntax (3): class Cat : Animal 11.10 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 10 20 11.9. Using ‘<’ and ‘:’ operators as ‘from’ keyword 166
Ring Documentation, Release 1.10 11.11 RingZip Library Ring 1.3 comes with the RingZip library for creating, modifying and extracting *.zip files. Example (1): Create myfile.zip contains 4 files load "ziplib.ring" oZip = zip_openfile("myfile.zip",'w') zip_addfile(oZip,"test.c") zip_addfile(oZip,"zip.c") zip_addfile(oZip,"zip.h") zip_addfile(oZip,"miniz.h") zip_close(oZip) Example (2): Extract myfile.zip to myfolder folder. load "ziplib.ring" zip_extract_allfiles("myfile.zip","myfolder") Example (3): Print file names in the myfile.zip load "ziplib.ring" oZip = zip_openfile("myfile.zip",'r') for x=1 to zip_filescount(oZip) see zip_getfilenamebyindex(oZip,x) + nl next zip_close(oZip) Example (4) : Using Classes instead of Functions load "ziplib.ring" new Zip { SetFileName("myfile.zip") Open("w") AddFile("test.c") AddFile("zip.c") AddFile("zip.h") AddFile("miniz.h") Close() } 11.12 Form Designer Ring 1.3 comes with the Form Designer to quickly design your GUI application windows/forms and generate the Ring source code. It’s written in Ring (Around 8000 Lines of code) using Object-Oriented Programming and Meta-Programming. We can run the From Designer from Ring Notepad 11.11. RingZip Library 167
Ring Documentation, Release 1.10 Also we can run the Form Designer in another window. 11.12. Form Designer 168
CHAPTER TWELVE WHAT IS NEW IN RING 1.2? In this chapter we will learn about the changes and new features in Ring 1.2 release. 12.1 List of changes and new features Ring 1.2 comes with many new features • New Functions • Better Functions • Better Ring Notepad • Better RingQt • Objects Library for RingQt • RingLibCurl • Better Call Command • Using NULL instead of NULLPointer() • Display Warnings Option • Better Quality 12.2 New Functions • PtrCmp() Function is a new function that compare between C pointers like the GUI objects. • PrevFileName() Function is added to return the previous active source file name. • RingVM_CFunctionsList() Function is added to return a list of functions written in C. • RingVM_FunctionsList() Function is added to return a list of functions written in Ring. • RingVM_ClassesList() Function is added to return a list of Classes. • RingVM_PackagesList() Function is added to return a list of Packages. • RingVM_MemoryList() Function is added to return a list of Memory Scopes and Variables. • RingVM_CallList() Function is added to return a list of the functions call list. • RingVM_FilesList() Function is added to return a list of the Ring Files. Example: 169
Ring Documentation, Release 1.10 fp = fopen("ptrcmp.ring","r") fp2 = fp fp3 = fopen("ptrcmp.ring","r") see ptrcmp(fp,fp2) + nl see ptrcmp(fp,fp3) + nl fclose(fp) fclose(fp3) Output: 1 0 Also we can compare between them using the ‘=’ operator Example: fp = fopen("ptrcmp2.ring","r") fp2 = fopen("ptrcmp2.ring","r") fp3 = fp see fp = fp2 see nl see fp = fp3 fclose(fp) fclose(fp2) Output: 0 1 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 12.3 Better Functions The find() function is updated to support searching in lists using C pointers like GUI Objects. The type() function is updated to display the C pointers types (like the GUI Object Class Name). 12.4 Better Ring Notepad The Ring Notepad will save the current line number of opened files to be restored when we switch between files. Also Ring Notepad will ask the user to save the file if the file content is changed when the user switch between files. 12.3. Better Functions 170
Ring Documentation, Release 1.10 12.5 Better RingQt RingQt classes are updated to include methods to get events (The code that will be executed when an event is fired). This is necessary to enable/disable events for some time or to get the events information. For example the next code disable an event then call a method then enable the event again. cEvent = oView.oListResult.getCurrentItemChangedEvent() oView.oListResult.setCurrentItemChangedEvent("") FindValueAction() # Call Method while an event is disabled oView.oListResult.setCurrentItemChangedEvent(cEvent) Also the QAllEvents class is updated where we can set the output from the event function to be true or false using a new method added to the class called setEventOutput. Load "guilib.ring" MyApp = New qApp { win = new qWidget() { setwindowtitle("Hello World") setGeometry(100,100,370,250) lineedit1 = new qlineedit(win) { setGeometry(10,100,350,30) setinputmask("9999;_") oFilter = new qallevents(lineedit1) oFilter.setfocusoutEvent("pMove()") installeventfilter(oFilter) } lineedit2 = new qlineedit(win) { setGeometry(10,150,350,30) } show() } exec() } func pMove win.setWindowTitle("xxxx") oFilter.setEventOutput(False) 12.6 Objects Library for RingQt Ring 1.2 comes with the Objects library for RingQt applications. Instead of using global variables for windows objects and connecting events to objects using the object name, the Objects Library will manage the GUI objects and will provide a more natural API to quickly create one or many windows from the same class and the 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. The Objects Library is designed to be used with the MVC Design Pattern. The Objects Library is merged in RingQt so you can use it directly when you use RingQt Example : load "guilib.ring" new qApp { 12.5. Better RingQt 171
Ring Documentation, Release 1.10 open_window( :MainWindowController ) exec() } class MainWindowController from WindowsControllerParent oView = new MainWindowView func SubWindowAction Open_window( :SubWindowController ) Last_Window().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 ) ) } resize(400,400) } 12.7 RingLibCurl The LibCurl library is used starting from Ring 1.0 for the Download() and SendEmail() functions implementation. In Ring 1.2 more functions are added to provide a powerful library (RingLibCurl) around LibCurl. Example: load "libcurl.ring" curl = curl_easy_init() cPostThis = "page=4&Number1=4&Number2=5" curl_easy_setopt(curl, CURLOPT_URL, "http://localhost/ringapp/index.ring?page=3") curl_easy_setopt(curl, CURLOPT_POSTFIELDS, cPostThis) 12.7. RingLibCurl 172
Ring Documentation, Release 1.10 curl_easy_perform(curl) curl_easy_cleanup(curl) 12.8 Better Call Command The Call command is updated to support calling functions from object attributes also (not only variables). For example the next code from the Stars Fighter Game cFunc = oself.keypress call cFunc(oGame,oSelf,Key_Space) Can be written in one line call oself.keypress(oGame,oSelf,Key_Space) 12.9 Using NULL instead of NULLPointer() We can pass NULL to functions instead of using NULLPointer() For example the next code from RingLibSDL SDL_RenderCopy(SDL_ren,tex,NULLPointer(),rect) Can be written as in the next line SDL_RenderCopy(SDL_ren,tex,NULL,rect) 12.10 Display Warnings Option In Ring 1.2 the Ring compiler is updated to include the Display Warnings option (-w) Example: load "stdlib.ring" load "stdlib.ring" compiling the program using the Display Warnings option will display the file duplication warning, While without that option the error will pass silent. This is a warning (not an error) because in large projects you may use the same file more than one time. For example it’s common to start each file with the next code. where the function IsMainSourceFile() is part from the stdlib.ring load "stdlib.ring" if IsMainSourceFile() // Testing ok 12.8. Better Call Command 173
Ring Documentation, Release 1.10 12.11 Better Quality Ring 1.2 is more stable, We discovered and fixed more bugs during Ring usage everyday in practical projects. Some functions are optimized to be faster like the SubStr() function. Also the documentation is more better. 12.11. Better Quality 174
CHAPTER THIRTEEN WHAT IS NEW IN RING 1.1? In this chapter we will learn about the changes and new features in Ring 1.1 release. 13.1 List of changes and new features Ring 1.1 comes with many new features • Better Natural Language Programming Support • Generate/Execute Ring Object Files (*.ringo) • Syntax Flexibility and different styles for I/O and Control Structures • New Functions and Changes • StdLib functions and classes written in Ring • RingLibSDL • Demo Project - Game Engine for 2D Games • RingSQLite • Better Code Generator for Extensions • Using Self.Attribute in the Class Region to define new attributes • Using This.Attribute in nested Braces inside the Class Methods • Better Documentation 13.2 Better Natural Language Programming Support Ring is an innovative language because of it’s compact syntax, smart implementation (small, transparent & visual) and it’s ability to create declarative and natural domain specific languages in a fraction of time. This release add support for calling methods when an expression is evaluated check this example: # Natural Code new program { Accept 2 numbers then print the sum } # Natural Code Implementation 175
Ring Documentation, Release 1.10 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 for more information see the “Natural Language Programming” chapter. 13.3 Generate/Execute Ring Object Files (*.ringo) This feature enable you to distribute your applications without distributing the source code. Also it makes application distribution a simple process where you get one Ring object file for the complete project (many source code files). Also using Ring object file remove the loading time required for compiling the application. Check the “command line options” chapter to know more about this feature. 13.4 Syntax Flexibility and different styles for I/O and Control Struc- tures Programmers are sensitive to the programming language syntax. Great programmers know how to work using many different styles but each programmer may have his/her favorite style. Each programming language comes with a style that you may like or not. Ring is just one of these languages, but as a response to many programmers asking for a better syntax we decided to provide more options. Also some of these features are very necessary for Natural Language Programming. Example : We have two commands to change language keywords and operators. ChangeRingOperator + plus ChangeRingKeyword see print Print 5 plus 5 13.3. Generate/Execute Ring Object Files (*.ringo) 176
Ring Documentation, Release 1.10 ChangeRingOperator plus + ChangeRingKeyword print see We have new styles (Optional) for Input/Output. Example : Put "What is your name? " Get cName Put "Hello " + cName Example : Load "stdlib.ring" Print("What is your name? ") # print message on screen cName=GetString() # get input from the user print("Hello #{cName}") # say hello! We have new styles (optional) for control structures. 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 Put "bad option..." + nl End End Example : Load "stdlib.ring" While True { print(" Main Menu --------- (1) Say Hello (2) About (3) Exit 13.4. Syntax Flexibility and different styles for I/O and Control Structures 177
Ring Documentation, Release 1.10 ") 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") } } Check the next chapters:- • Getting Started - Second Style • Getting Started - Third Style • Control Structures - Second Style - May looks like Lua and Ruby • Control Structures - Third Style - May looks like C (uses braces) • Syntax Flexibility Note: All of these styles are provided automatically by the compiler at the same time, It’s better to select one style for the same project (you can create your style as a mix from these styles) for example you can use Put/Get and Braces. 13.5 New Functions and Changes Changed: • get() function : changed to sysget() • sort() function : can now work on list of objects • find() function : can now work on list of objects Added: • clockspersecond() • CurrentDir() • ExeFileName() • ChDir() • ExeFolder() • varptr() • space() • nullpointer() 13.5. New Functions and Changes 178
Ring Documentation, Release 1.10 • object2pointer() • pointer2object() Check the next chapters • System Functions • Object Oriented Programming (OOP) • Low Level Functions 13.6 StdLib functions and classes written in Ring Ring 1.1 comes with a library called StdLib, it’s written in Ring by the help of Ring Team The library provide a useful group of new functions and classes Example: Load "stdlib.ring" Puts("Test Times()") Times ( 3 , func { see "Hello, World!" + nl } ) Example: Load "stdlib.ring" Puts("Test Map()") See Map( 1:10, func x { return x*x } ) Example: Load "stdlib.ring" Puts("Test Filter()") See Filter( 1:10 , func x { if x <= 5 return true else return false ok } ) 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() oString.right(6).println() Example: Load "stdlib.ring" oList = new list ( [1,2,3] ) oList.Add(4) oList.print() Example: 13.6. StdLib functions and classes written in Ring 179
Ring Documentation, Release 1.10 Load "stdlib.ring" oStack = new Stack oStack.push(1) oStack.push(2) oStack.push(3) see oStack.pop() + nl Example: Load "stdlib.ring" oQueue = new Queue oQueue.add(1) oQueue.add(2) oQueue.add(3) see oQueue.remove() + nl 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() } 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") 13.6. StdLib functions and classes written in Ring 180
Ring Documentation, Release 1.10 } } oTree.children[2].children[3].children[3].set("2.3.3") } see copy("*",60) + nl oTree.print() Check the next chapters: • StdLib Functions • StdLib Classes 13.7 RingLibSDL Ring 1.0 provided RingAllegro to be able to create games using the Allegro game programming library Now Ring 1.1 provide RingLibSDL also so we can have the choice between Allegro or LibSDL Example: Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN) SDL_Delay(2000) SDL_DestroyWindow(win) SDL_Quit() See the RingLibSDL Chapter. 13.8 Demo Project - Game Engine for 2D Games In practice we would create a game engine in a language like C/C++ to get the best performance then provide Ring classes to use the engine. But many 2D Games are simple and creating a game engine in Ring will be fast enough in many cases Also this would be a good demo project to learn about the language concepts where we build things using Object Ori- ented Programming (OOP) then access the power that we have using declarative programming using nested structures or using natural programming. In this project we selected the first way (declarative programming using nested structures) 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" text { x = 10 y=50 animate = false size = 20 13.7. RingLibSDL 181
Ring Documentation, Release 1.10 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 See the “Demo Project - Game Engine for 2D Games” chapter. 13.9 RingSQLite Ring 1.0 provided support for ODBC to use any database and provided native support for MySQL. Now Ring 1.1 provide native support for SQLite database too. Example: 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 ); " + "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 );" sqlite_execute(oSQLite,sql) aResult = sqlite_execute(oSQLite,"select * from COMPANY") 13.9. RingSQLite 182
Ring Documentation, Release 1.10 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 sqlite_close(oSQLite) 13.10 Better Code Generator for Extensions We are using the code generator (written in Ring) every day to add new libraries to Ring. The generator is used to create RingQt and RingAllegro Also in Ring 1.1 it’s used to create RingLibSDL. more features are added like • Set/Get structure members (numbers & pointers) • Using constants • Better Generated Code See the Code Generator chapter. 13.11 Using Self.Attribute in the Class Region to define new at- tributes We can use Self.Attribute in the Class Region (after the class name and before any methods) to define new attributes. class Person name # Define name as attribute if it's not a global variable address phone class person2 self.name # Must Define the attribute self.address self.phone 13.12 Using This.Attribute in nested Braces inside the Class Methods We can use nested braces {} while we are inside methods to access another objects, In this case the current object scope will be changed while we are inside the brace and Self will point to the object that we access using braces {}. In this case we can use This.Attribute and This.Method() to access the object that will be created from the current class. Check the Object Oriented Programming chapter for more information. Also Check the Weight History Application in GUI Development using RingQt chapter. 13.10. Better Code Generator for Extensions 183
Ring Documentation, Release 1.10 13.13 Better Documentation Ring 1.1 documentation (800 pages) is better than Ring 1.0 documentation (340 pages) Many chapters are added for providing better information about the language like • Language Reference • Scope Rules • FAQ And more! 13.13. Better Documentation 184
CHAPTER FOURTEEN BUILDING FROM SOURCE CODE The Ring programming language is a free open source product (MIT License). You can build Ring using CMake or using Scripts (Batch Files or Shell Scripts). The next steps explains building using scripts. 14.1 Building using Microsoft Windows Get the source code git clone http://github.com/ring-lang/ring.git Build Ring (Compiler/VM) cd ring/src buildvc.bat buildvcw.bat Build Ring2EXE cd ../ring2exe buildring2exe.bat Generate RingConsoleColors Source Code and Build cd ../extensions/ringconsolecolors gencode.bat buildvc.bat Build RingInternet cd ../extensions/ringinternet buildvc.bat Generate RingLibCurl Source Code and Build cd ../extensions/ringcurl gencode.bat buildvc.bat Build RingPM cd ../ringpm buildringpm.bat 185
Ring Documentation, Release 1.10 Build RingODBC cd ../extensions/ringodbc buildvc.bat Build RingMySQL cd ../extensions/ringmysql buildvc.bat Build RingSQLite cd ../extensions/ringsqlite buildvc.bat Build RingPostgreSQL cd ../extensions/ringpostgresql gencode.bat buildvc.bat Build RingOpenSSL cd ../extensions/ringopenssl buildvc.bat Build RingMurmurHash cd ../extensions/ringmurmurhash buildvc.bat Generate RingAllegro Source Code and Build cd ../extensions/ringallegro gencode.bat buildvc.bat Generate RingZip Source Code and Build cd ../extensions/ringzip gencode.bat buildvc.bat Generate RingLibuv Source Code and Build cd ../extensions/ringlibuv gencode.bat buildvc.bat Generate RingFreeGLUT Source Code and Build cd ../extensions/ringfreeglut gencode.bat buildvc.bat Generate RingOpenGL Source Code and Build The ringopengl folder contains many sub folders for different OpenGL versions Starting from OpenGL 1.1 to OpenGL 4.6 cd ../extensions/ringopengl/opengl21 gencode.bat buildvc.bat 14.1. Building using Microsoft Windows 186
Ring Documentation, Release 1.10 Generate RingPostgreSQL Source Code and Build cd ../extensions/ringpostgresql gencode.bat buildvc.bat Install Qt 5.5 : https://download.qt.io/archive/qt/5.5/5.5.1/ Generate RingQt Source Code and Build cd ../extensions/ringqt gencode.bat buildmingw32.bat To be able to call ring from any folder cd ../../bin install.bat Add Ring/bin to System path Hit "windows key". Type "Edit the System environment variables" Select "Advanced" tab. Click on "Enviroment Variables..." Double click on "Path" Add at the end the new path separated by semicolon. ;C:RingBin Run Ring Notepad cd applications/rnote ring rnote.ring 14.2 Building using Ubuntu Linux Get the source code git clone http://github.com/ring-lang/ring.git Install Libraries cd ring/src ./installdep.sh Build Ring (Compiler/VM) sudo ./buildgcc.sh Build Ring2EXE cd ../ring2exe sudo ./buildring2exe.sh Generate RingConsoleColors Source Code and Build cd ../extensions/ringconsolecolors ./gencode.sh ./buildgcc.sh 14.2. Building using Ubuntu Linux 187
Ring Documentation, Release 1.10 Build RingInternet cd ../extensions/ringinternet ./buildgcc.sh Generate RingLibCurl Source Code and Build cd ../extensions/ringcurl ./gencode.sh ./buildgcc.sh Build RingPM cd ../ringpm sudo ./buildringpm.sh Build RingODBC cd ../extensions/ringodbc ./buildgcc.sh Build RingMySQL cd ../extensions/ringmysql ./buildgcc.sh Build RingSQLite cd ../extensions/ringsqlite ./buildgcc.sh Build RingPostgreSQL cd ../extensions/ringpostgresql gencode.sh buildgcc.sh Build RingOpenSSL cd ../extensions/ringopenssl ./buildgcc.sh Build RingMurmurHash cd ../extensions/ringmurmurhash ./buildgcc.sh Generate RingAllegro Source Code and Build cd ../extensions/ringallegro ./gencode.sh ./buildgcc.sh Generate RingZip Source Code and Build cd ../extensions/ringzip ./gencode.sh ./buildgcc.sh Generate RingLibuv Source Code and Build We will build Libuv first 14.2. Building using Ubuntu Linux 188
Ring Documentation, Release 1.10 cd ../extensions/ringlibuv/libuv sudo apt-get install libtool m4 automake sh autogen.sh ./configure make make check sudo make install Then we will build RingLibuv cd .. ./gencode.sh ./buildgcc.sh Generate RingFreeGLUT Source Code and Build cd ../extensions/ringfreeglut ./gencode.sh ./buildgcc.sh Generate RingOpenGL Source Code and Build The ringopengl folder contains many sub folders for different OpenGL versions Starting from OpenGL 1.1 to OpenGL 4.6 cd ../extensions/ringopengl/opengl21 gencode.sh buildgcc.sh Generate RingPostgreSQL Source Code and Build cd ../extensions/ringpostgresql ./gencode.sh ./buildgcc.sh Generate RingQt Source Code and Build cd ../extensions/ringqt ./gencode.sh ./buildgcc.sh To be able to call ring from any folder cd ../../bin sudo ./install.sh Run Ring Notepad cd applications/rnote ring rnote.ring 14.3 Building using Fedora Linux Get the source code git clone http://github.com/ring-lang/ring.git Install Libraries 14.3. Building using Fedora Linux 189
Ring Documentation, Release 1.10 cd ring/src ./installdepfedora.sh Build Ring (Compiler/VM) sudo ./buildgcc.sh Build Ring2EXE cd ../ring2exe sudo ./buildring2exe.sh Generate RingConsoleColors Source Code and Build cd ../extensions/ringconsolecolors ./gencode.sh ./buildgcc.sh Build RingInternet cd ../extensions/ringinternet ./buildgcc.sh Generate RingLibCurl Source Code and Build cd ../extensions/ringcurl ./gencode.sh ./buildgcc.sh Build RingPM cd ../ringpm sudo ./buildringpm.sh Build RingODBC cd ../extensions/ringodbc ./buildgcc.sh Build RingMySQL cd ../extensions/ringmysql ./buildgccfedora.sh Build RingSQLite cd ../extensions/ringsqlite ./buildgcc.sh Build RingPostgreSQL cd ../extensions/ringpostgresql gencode.sh buildgcc.sh Build RingOpenSSL cd ../extensions/ringopenssl ./buildgcc.sh Build RingMurmurHash 14.3. Building using Fedora Linux 190
Ring Documentation, Release 1.10 cd ../extensions/ringmurmurhash ./buildgcc.sh Generate RingAllegro Source Code and Build cd ../extensions/ringallegro ./gencode.sh ./buildgcc.sh Generate RingZip Source Code and Build cd ../extensions/ringzip ./gencode.sh ./buildgcc.sh Generate RingLibuv Source Code and Build We will build Libuv first cd ../extensions/ringlibuv/libuv sudo dnf install libtool m4 autoconf automake sh autogen.sh ./configure make make check sudo make install Then we will build RingLibuv cd .. ./gencode.sh ./buildgcc.sh Generate RingFreeGLUT Source Code and Build cd ../extensions/ringfreeglut ./gencode.sh ./buildgcc.sh Generate RingOpenGL Source Code and Build The ringopengl folder contains many sub folders for different OpenGL versions Starting from OpenGL 1.1 to OpenGL 4.6 cd ../extensions/ringopengl/opengl21 gencode.sh buildgcc.sh Generate RingPostgreSQL Source Code and Build cd ../extensions/ringpostgresql ./gencode.sh ./buildgcc.sh Generate RingQt Source Code and Build cd ../extensions/ringqt ./gencode.sh ./buildgccfedora.sh To be able to call ring from any folder 14.3. Building using Fedora Linux 191
Ring Documentation, Release 1.10 cd ../../bin sudo ./install.sh Run Ring Notepad cd applications/rnote ring rnote.ring 14.4 Building using MacOS X Get the source code git clone http://github.com/ring-lang/ring.git Install homebrew (follow the directions on homebrew’s homepage). Install Libraries cd ring/src ./installdepmac.sh Build Ring (Compiler/VM) ./buildclang.sh Build Ring2EXE cd ../ring2exe sudo ./buildring2exe.sh Generate RingConsoleColors Source Code and Build cd ../extensions/ringconsolecolors ./gencode.sh ./buildclang.sh Build RingInternet cd ../extensions/ringinternet ./buildclang.sh Generate RingLibCurl Source Code and Build cd ../extensions/ringcurl ./gencode.sh ./buildclang.sh Build RingPM cd ../ringpm sudo ./buildringpm.sh Build RingODBC cd ../extensions/ringodbc ./buildclang.sh Build RingMySQL cd ../extensions/ringmysql ./buildclang.sh 14.4. Building using MacOS X 192
Ring Documentation, Release 1.10 Build RingSQLite cd ../extensions/ringsqlite ./buildclang.sh Build RingPostgreSQL cd ../extensions/ringpostgresql gencode.sh buildclang.sh Build RingOpenSSL cd ../extensions/ringopenssl ./buildclang.sh Build RingMurmurHash cd ../extensions/ringmurmurhash ./buildclang.sh Generate RingAllegro Source Code and Build cd ../extensions/ringallegro ./gencode.sh ./buildclang.sh Generate RingZip Source Code and Build cd ../extensions/ringzip ./gencode.sh ./buildclang.sh Generate RingLibuv Source Code and Build cd ../extensions/ringlibuv ./gencode.sh ./buildclang.sh Generate RingFreeGLUT Source Code and Build cd ../extensions/ringfreeglut ./gencode.sh ./buildclang.sh Generate RingOpenGL Source Code and Build The ringopengl folder contains many sub folders for different OpenGL versions Starting from OpenGL 1.1 to OpenGL 4.6 cd ../extensions/ringopengl/opengl21 ./gencode.sh ./buildclang.sh Generate RingPostgreSQL Source Code and Build cd ../extensions/ringpostgresql ./gencode.sh ./buildclang.sh Generate RingQt Source Code and Build 14.4. Building using MacOS X 193
Ring Documentation, Release 1.10 cd ../extensions/ringqt ./gencodemac.sh ./buildclang.sh To be able to call ring from any folder cd ../../bin sudo ./install.sh Run Ring Notepad cd applications/rnote sudo ring rnote.ring 14.5 Building using CMake Install libraries (MySQL Client, OpenSSL, LibCurl, Allegro 5 and Qt 5.5) cmake . make 14.5. Building using CMake 194
CHAPTER FIFTEEN HOW TO CONTRIBUTE? Ring is a free-open source project, Everyone is welcome to contribute to Ring. Project Home : https://github.com/ring-lang/ring You can help in many parts in the project • Documentation • Testing • Samples • Applications • Editors Support • Libraries in Ring • Extensions in C/C++ • Compiler and Virtual Machine (VM) • Ideas and suggestions 15.1 Special thanks to contributors Throughout the creation of this project, Ring relied heavily on contributions from experts along with college students. Their input was invaluable, and we want to take a moment to thank them and recognize them for all of their hard work. Ring Team: http://ring-lang.sf.net/team.html 15.2 Documentation You can modify anything in the documentation, by updating the text files (*.txt) in this folder : https://github.com/ring- lang/ring/tree/master/docs/source The documentation is created using Sphinx : http://www.sphinx-doc.org/en/stable/ 15.3 Testing You can write new tests in this folder https://github.com/ring-lang/ring/tree/master/tests/scripts 195
Ring Documentation, Release 1.10 15.4 Samples You can add new samples to this folder https://github.com/ring-lang/ring/tree/master/samples/other 15.5 Applications You can add new applications to this folder https://github.com/ring-lang/ring/tree/master/applications 15.6 Editors Support You can help in supporting Ring in different code editors Check the next folder https://github.com/ring-lang/ring/tree/master/editor 15.7 Libraries in Ring You can update and add libraries to this folder https://github.com/ring-lang/ring/tree/master/ringlibs 15.8 Extensions in C/C++ You can add and update extensions in this folder https://github.com/ring-lang/ring/tree/master/extensions 15.9 Compiler and Virtual Machine (VM) • Source Code (C Language) : https://github.com/ring-lang/ring/tree/master/src • Visual Source (PWCT) : https://github.com/ring-lang/ring/tree/master/visualsrc 15.10 Ideas and suggestions You can share your ideas, suggestions and questions in this group https://groups.google.com/forum/#!forum/ring-lang 15.4. Samples 196
CHAPTER SIXTEEN GETTING STARTED - FIRST STYLE 16.1 Hello World The next program prints the Hello World message on the screen (std-out). see "Hello World" 16.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 16.3 Create Executable File Using Ring2EXE we can create executable file for our application ring2exe hello.ring -static 16.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" 16.5 Multi-Line literals Using Ring we can write multi-line literal, see the next example 197
Ring Documentation, Release 1.10 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?" 16.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 16.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 16.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: Hello, World! 1 2 3 4 5 6 7 8 16.6. Getting Input 198
Ring Documentation, Release 1.10 9 10 16.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. 16.9. Writing Comments 199
CHAPTER SEVENTEEN GETTING STARTED - SECOND STYLE 17.1 Hello World The next program prints the Hello World message on the screen (std-out). put "Hello World" 17.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 17.3 Create Executable File Using Ring2EXE we can create executable file for our application ring2exe hello.ring -static 17.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" 17.5 Multi-Line literals Using Ring we can write multi-line literal, see the next example 200
Ring Documentation, Release 1.10 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?" 17.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 17.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 17.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 */ 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. 17.6. Getting Input 201
CHAPTER EIGHTEEN GETTING STARTED - THIRD STYLE 18.1 Hello World The next program prints the Hello World message on the screen (std-out). load "stdlib.ring" print("Hello World") 18.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 18.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 ring2exe hello.ring -dist -allruntime -noqt -noallegro 202
Ring Documentation, Release 1.10 18.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") 18.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?") 18.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}") 18.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}") 18.8 Writing Comments We can write one line comments and multi-line comments 18.4. Not Case-Sensitive 203
Ring Documentation, Release 1.10 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. 18.8. Writing Comments 204
CHAPTER NINETEEN USING RING NOTEPAD In this 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. 19.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 205
Ring Documentation, Release 1.10 19.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 19.2. Creating and running your first Console Application 206
Ring Documentation, Release 1.10 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. 19.2. Creating and running your first Console Application 207
Ring Documentation, Release 1.10 19.3 Creating and running your first GUI/Mobile Application To learn how to create GUI applications using Ring check the “Desktop 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. 19.3. Creating and running your first GUI/Mobile Application 208
Ring Documentation, Release 1.10 The next screen shot present the application during the runtime 19.4 Creating and running your first Web Application To learn how support Ring in your web server and how to create web applications using Ring check the “Web Devel- opment (CGI Library)” chapter. Note: You need to support the Ring language in your web server to be able to run the next example. 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. 19.4. Creating and running your first Web Application 209
Ring Documentation, Release 1.10 For Windows users, Ring comes with Apache Web server! We can run any web application from any folder directly without doing any configuration. 19.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: 19.5. Creating and running your first Desktop/Mobile Game 210
Ring Documentation, Release 1.10 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. 19.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 19.6. The Main File in the Project 211
Ring Documentation, Release 1.10 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: 19.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” 19.7. The File Menu 212
Ring Documentation, Release 1.10 19.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. 19.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) 19.8. The Edit Menu 213
Ring Documentation, Release 1.10 Also we can quickly show/hide group of dockable windows based on the context 19.9. The View Menu 214
Ring Documentation, Release 1.10 19.10 The Program Menu From this menu we can run the programs Also we can set the Main file in the project 19.11 The Browser Menu From this menu we can quickly open common links in the browser 19.10. The Program Menu 215
Ring Documentation, Release 1.10 19.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 19.13 The Distribute Menu From this menu we can build an executable file for the application Also we can prepare the application for distribution 19.12. The Tools Menu 216
Ring Documentation, Release 1.10 19.14 The Help Menu From this menu we can get the help files (CHM & PDF) 19.14. The Help Menu 217
CHAPTER TWENTY USING OTHER CODE EDITORS In the Ring/Editor folder you will find extensions for the next editors • Notepad++ • Geany • Atom • Sublime Text 2 • Visual Studio IDE • Emacs • Visual Studio Code (VSCode) 20.1 Using Notepad++ Folder : ring/editor/notepad_plus_plus • Open Notepad++ • Open the “Language” menu • Select “Define your language...” • Click “Import...” • select Ring.xml • Select “OK” on the “Import successful” dialog and close the “User Defined Language” dialog/panel • You may need to restart notepad++ 218
Ring Documentation, Release 1.10 20.2 Using Geany Folder : ring/editor/geany • Run Geany editor • Click on “Tools -> configuration files -> filetypes_extensions.conf” menu • Add this line “Ring=*.ring;” without quotes after [Extensions] • In unbuntu copy file “filetypes.Ring.conf” to folder “/home/USERNAME/filetypes.Ring.conf” • You can run your files by pressing F5 button 20.2. Using Geany 219
Ring Documentation, Release 1.10 20.3 Using Atom Folder : ring/editor/atom Just Copy the folder atom-language-ring to the next path "C:Users{UserName}.atomPackages" 20.3. Using Atom 220
Ring Documentation, Release 1.10 20.4 Using Sublime Text 2 Folder : ring/editor/sublime text 2 In the folder Sublime_Text_2 you will find the next three files 1 - ring.json-tmlanguage 2 - ring.sublime-build 3 - ring.tmlanguage Just Copy the files to the next path "C:Users{UserName}AppDataRoamingSublime Text 2PackagesUser" The file ring.sublime-build includes the next line "cmd": ["B:ringbinring.exe","$file"], You can modify it according to the ring.exe path in your machine 20.4. Using Sublime Text 2 221
Ring Documentation, Release 1.10 20.5 Using Visual Studio IDE Folder : ring/editor/visualstudio Check the ReadMe file for installation instructions. 20.5. Using Visual Studio IDE 222
Ring Documentation, Release 1.10 20.6 Using Emacs Editor Folder : ring/editor/emacs Check the ReadMe file for installation instructions. Screen Shot: 20.7 Visual Studio Code Folder : ring/vscode Check the ReadMe file for installation instructions. Screen Shot: 20.6. Using Emacs Editor 223
Ring Documentation, Release 1.10 20.7. Visual Studio Code 224
CHAPTER TWENTYONE VARIABLES To create a new 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). 21.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 21.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 225
Ring Documentation, Release 1.10 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 21.3 Weakly Typed Ring is a weakly typed language, this means that the language can automatically convert between data types (like string & numbers) when that conversion make sense. 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 21.3. Weakly Typed 226
CHAPTER TWENTYTWO OPERATORS In this chapter we will introduce the operators provided by the Ring programming langauge. 22.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 22.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 22.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 227
Ring Documentation, Release 1.10 Another style Operator Description Example Result && Logical AND x && y False || Logical OR x || y True ! Logical Not ! x False 22.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 22.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 22.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 22.4. Bitwise Operators 228
Ring Documentation, Release 1.10 22.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 22.7. Operators Precedence 229
CHAPTER TWENTYTHREE CONTROL STRUCTURES - FIRST STYLE In this chapter we are going to learn about the control structures provided by the Ring programming language. 23.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 230
Ring Documentation, Release 1.10 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 23.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 Syntax: 23.2. Looping 231
Ring Documentation, Release 1.10 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 23.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 23.3. Using The Step option with For in 232
Ring Documentation, Release 1.10 23.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 23.5 Do Again Loop Syntax: do Block of statements again expression Example: x = 1 do see x + nl x++ again x <= 10 23.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 23.4. Using For in to modify lists 233
Ring Documentation, Release 1.10 23.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 23.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 23.9 Exit/Loop inside sub functions While we are inside a loop, we can call a function then use the exit and/or loop command inside that function and the command will work on the outer loop. Example: # print numbers from 1 to 10 except number 5. for x = 1 to 10 ignore(x,5) see x + nl next func ignore x,y if x = y loop ok 23.7. Exit from two loops 234
Ring Documentation, Release 1.10 23.10 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 23.11 Comments about evaluation • True, False, nl & NULL are variables defined by the language • True = 1 23.10. Short-circuit evaluation 235
Ring Documentation, Release 1.10 • 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 23.11. Comments about evaluation 236
CHAPTER TWENTYFOUR 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. 24.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 Block of statements end 237
Ring Documentation, Release 1.10 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 24.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 Put "bad option..." + nl End End • For Loop Syntax: 24.2. Looping 238
Ring Documentation, Release 1.10 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 24.3 Exceptions try Block of statements catch Block of statements end 24.3. Exceptions 239
CHAPTER TWENTYFIVE 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. 25.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") } 240
Ring Documentation, Release 1.10 • 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") } 25.2 Looping • While Loop Syntax: while Expression { Block of statements } Example: Load "stdlib.ring" While True { print(" Main Menu --------- 25.2. Looping 241
Ring Documentation, Release 1.10 (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" # print even numbers from 0 to 10 for x = 0 to 10 step 2 { print("#{x}n") } 25.2. Looping 242
Ring Documentation, Release 1.10 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" } } print(aList) # print the list items 25.3 Exceptions 25.3. Exceptions 243
Ring Documentation, Release 1.10 try { Block of statements catch Block of statements } 25.3. Exceptions 244
CHAPTER TWENTYSIX GETTING INPUT We can get input from the keyboard using • The Give Command • The GetChar() Function • The Input() Function 26.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 26.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 (2) Exit " Option = GetChar() 245
Ring Documentation, Release 1.10 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 26.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 26.3. Input() Function 246
CHAPTER TWENTYSEVEN FUNCTIONS - FIRST STYLE 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 27.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 27.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: 247
Ring Documentation, Release 1.10 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 27.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 27.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 27.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: 27.3. Declare parameters 248
Ring Documentation, Release 1.10 # 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 27.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. 27.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: 27.6. Variables Scope 249
Ring Documentation, Release 1.10 if novalue() = NULL See "the function doesn't return a value" + nl ok func novalue 27.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 27.8. Recursion 250
CHAPTER TWENTYEIGHT FUNCTIONS - SECOND STYLE 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 28.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 28.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: 251
Ring Documentation, Release 1.10 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 28.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 28.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 28.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: 28.3. Declare parameters 252
Ring Documentation, Release 1.10 # 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 28.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. 28.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: 28.6. Variables Scope 253
Ring Documentation, Release 1.10 if novalue() = NULL put "the function doesn't return a value" + nl end def novalue 28.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 28.8. Recursion 254
CHAPTER TWENTYNINE FUNCTIONS - THIRD STYLE 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 29.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") } 29.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: 255
Ring Documentation, Release 1.10 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") } 29.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) } 29.4 Send Parameters To send parameters to function, type the parameters inside () after the function name Syntax: funcname(parameters) Example: /* output ** 8 ** 3000 */ load "stdlib.ring" sum(3,5) sum(1000,2000) func sum(x,y) { print(x+y) } 29.3. Declare parameters 256
Ring Documentation, Release 1.10 29.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") } 29.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 { 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. 29.7 Return Value The function can return a value using the Return command. Syntax: 29.5. Main Function 257
Ring Documentation, Release 1.10 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 { } 29.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) } } 29.8. Recursion 258
CHAPTER THIRTY PROGRAM STRUCTURE In this chapter we will learn about using many source code files in the same project. 30.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. 30.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") # File : sub.ring func sayhello cName see "Hello " + cName + nl 259
Ring Documentation, Release 1.10 30.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 30.3. Load Package 260
CHAPTER THIRTYONE LISTS In this chapter we are going to learn how to deal with lists. 31.1 Create Lists We can create new lists by defining the list items inside square bracts. 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) Example aList = list(10) # aList contains 10 items Note: the list index start from 1 31.2 Add Items To add new items to the list, we can use the Add() function. Syntax: Add(List,Item) 261
Ring Documentation, Release 1.10 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 31.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 31.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 31.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 31.3. Get List Size 262
Ring Documentation, Release 1.10 31.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 31.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: 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 31.6. Set List Item 263
Ring Documentation, Release 1.10 31.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 Output: ahmed 14000 ibrahim 11000 mahmoud 15000 mohammed 12000 samir 16000 31.9 Reverse We can reverse a list using the reverse() function. Syntax: 31.8. Sort 264
Ring Documentation, Release 1.10 Reverse(List) ---> Reversed List Example: aList = [10,20,30,40,50] aList = reverse(aList) see aList # print 50 40 30 20 10 31.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 31.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 31.12 Copy Lists We can copy lists (including nested lists) using the Assignment operator. Example: 31.10. Insert Items 265
Ring Documentation, Release 1.10 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 31.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 nMax = len(list) for x = 1 to nMax list + list[x] next return list func mylist return [10,20,30,40,50] 31.14 Using Lists during definition We can use 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 31.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 31.13. First-class lists 266
Ring Documentation, Release 1.10 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] 31.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 31.17 Passing Parameters or Argumnents 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: 31.16. Access List Items by String Index 267
Ring Documentation, Release 1.10 myconnect ( [ :server = "myserver.com" , :port = 80 , :username = "mahmoud" , :password = "password" ] ) func myconnect mypara # print connection details see "User Name : " + mypara[:username] + nl + "Password : " + mypara[:password] + nl + "Server : " + mypara[:server] + nl + "Port : " + mypara[:port] 31.18 Passing Parameters or Argumnents Using List Array Passing Arguments or Parmameters 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 31.19 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 31.18. Passing Parameters or Argumnents Using List Array 268
Ring Documentation, Release 1.10 next ###----------------------------------------------- ### 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 dimesions: 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 31.20 Swap Items We can swap the list items using the Swap() function. Example: aList = [:one,:two,:four,:three] see aList 31.20. Swap Items 269
Ring Documentation, Release 1.10 see copy("*",50) + nl swap(aList,3,4) see aList Output one two four three ************************************************** one two three four 31.20. Swap Items 270
CHAPTER THIRTYTWO STRINGS In this chapter we are going to learn about strings creation and manipulation. 32.1 String Literals Syntax: cStr = "This is a string" cStr2 = 'Another string' cStr3 = :JustAnotherString cStr4 = `Yet "another" 'string' ! ` 32.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 32.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) 271
Ring Documentation, Release 1.10 32.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 32.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 32.6 Right() Function We can get a specified number of characters from a string using the Right() function. 32.4. Access String Letters 272
Ring Documentation, Release 1.10 The starting position is the last character on the right. Syntax: Right(string,count) Example: see Right("Hello World!",6) # print World! 32.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 32.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*** 32.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: cStr = "Hello How are you? are you fine?" see lines(cStr) # print 3 32.7. Trim() Function 273
Ring Documentation, Release 1.10 32.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 32.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 32.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 32.13 Get Number of Characters From Position Syntax: substr(string,position,count) ---> Get characters starting from position Example: cStr = "Welcome to the Ring programming language" nPos = substr(cStr,"Ring") # nPos = 16 see substr(cStr,nPos,4) # print Ring 32.14 Transform Substring To Another Substring Syntax: 32.10. Substr() Function 274
Ring Documentation, Release 1.10 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 32.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 32.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: /* 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 */ 32.15. strcmp() Function 275
Ring Documentation, Release 1.10 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 32.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 ? "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] 32.17. Merge binary characters 276
Ring Documentation, Release 1.10 ? 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 32.17. Merge binary characters 277
CHAPTER THIRTYTHREE DATE AND TIME In this chapter we are going to learn about the date and time functions. 33.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 33.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 33.3 Time() Function We can get the system time using the Time() function. Example: See "Time : " + time() 278
Ring Documentation, Release 1.10 33.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 33.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 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) 33.4. Date() Function 279
Ring Documentation, Release 1.10 ** 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 Example: See "Month Name : " + TimeList()[4] # May 33.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 33.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 33.6. AddDays() Function 280
Ring Documentation, Release 1.10 33.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, "/") arrayTime = split(Time, ":") Year = arrayDate[3] ; Month = arrayDate[2] ; Day = arrayDate[1] Hour = arrayTime[1] ; Minute = arrayTime[2] ; Second = arrayTime[3] cDate1 = Day +"/"+ Month +"/"+ Year cDate2 = "01/01/" + Year DayOfYear = DiffDays( cDate1, cDate2) ### Formula tm_sec = Second * 1 tm_min = Minute * 60 tm_hour = Hour * 3600 tm_yday = DayOfYear * 86400 tm_year = Year - 1900 tm_year1 = ( tm_year - 70) * 31536000 tm_year2 = ( floor(( tm_year - 69) / 4 )) * 86400 tm_year3 = ( floor(( tm_year - 1) / 100 )) * 86400 tm_year4 = ( floor(( tm_year + 299) / 400 )) * 86400 ### Result EpochSec = tm_sec + tm_min + tm_hour + tm_yday + tm_year1 + tm_year2 - tm_year3 + tm_year4 return EpochSec 33.8. EpochTime() Function 281
CHAPTER THIRTYFOUR CHECK DATA TYPE AND CONVERSION In this chapter we are going to learn about the functions that can be used for • Checking Data Type • Checking Character • Conversion 34.1 Check Data Type The next functions can be used to check the data type • isstring() • isnumber() • islist() • type() • isnull() 34.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 34.3 IsNumber() Function Using the IsNumber() function we can know if the value is a number or not Syntax: 282
Ring Documentation, Release 1.10 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 34.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 34.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 34.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: 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 34.4. IsList() Function 283
Ring Documentation, Release 1.10 34.7 Check Character The next functions can be used to check character • isalnum() • isalpha() • iscntrl() • isdigit() • isgraph() • islower() • isprint() • ispunct() • isspace() • isupper() • isxdigit() 34.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 34.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 34.7. Check Character 284
Ring Documentation, Release 1.10 34.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 34.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 34.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: see isgraph("abcdef") + nl + # print 1 isgraph("abc def") # print 0 34.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 34.10. IsCntrl() Function 285
Ring Documentation, Release 1.10 34.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 34.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 34.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 34.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 34.14. IsPrint() Function 286
Ring Documentation, Release 1.10 34.18 IsXdigit() Function We can test a character or a string using the IsXdigit() Function Syntax: IsXdigit(value) ---> 1 if the value is a hexdecimal digit character or 0 if not Example: see isxdigit("0123456789abcdef") + nl + # print 1 isxdigit("123z") # print 0 34.19 Conversion The next functions can be used for conversion • number() • string() • ascii() • char() • hex() • dec() • str2hex() • hex2str() 34.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 34.21 String() Function We can convert numbers to strings using the String() function or the + operator. Syntax: String(number) ---> String "" + number ---> String 34.18. IsXdigit() Function 287
Ring Documentation, Release 1.10 Example: see string(5) + 5 + nl # print 55 see "" + 10 + 2 # print 102 34.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 34.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 34.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 34.25 Dec() Function We can convert hexadecimal to decimal using the Dec() function Syntax: Dec(hexadecimal) ---> decimal 34.22. Ascii() Function 288
Ring Documentation, Release 1.10 Example: See dec("a") + nl + # print 10 dec("c8") # print 200 34.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 34.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 34.26. Str2hex() Function 289
CHAPTER THIRTYFIVE MATHEMATICAL FUNCTIONS In this chapter we are going to learn about the mathematical functions 35.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 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 35.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 290
Ring Documentation, Release 1.10 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 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 35.2. Example 291
Ring Documentation, Release 1.10 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 35.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 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 35.3. Random() Function 292
Ring Documentation, Release 1.10 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 35.4 SRandom() Function The SRandom() function initialize random number generator. Syntax: SRandom(x) 35.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: 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 35.4. SRandom() Function 293
Ring Documentation, Release 1.10 Output: 3372029979.00 35.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 35.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 35.6. Decimals() Functions 294
Ring Documentation, Release 1.10 35.8 Using f after numbers We can use the ‘f’ letter after numbers. Example: x = 19.99f see type(x) + nl Output: NUMBER 35.8. Using f after numbers 295
CHAPTER THIRTYSIX FILES In this chapter we are going to learn about files functions. • Read() • Write() • Dir() • Rename() • Remove() • fopen() • fclose() • fflush() • freopen() • tempfile() • tempname() • fseek() • ftell() • rewind() • fgetpos() • fsetpos() • clearerr() • feof() • ferror() • perror() • fgetc() • fgets() • fputc() • fputs() • ungetc() • fread() 296
Ring Documentation, Release 1.10 • fwrite() • fexists() • Numbers and Bytes 36.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") 36.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) 36.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 • Type (0 = File , 1 = Folder/Directory) Example: 36.1. Read() Function 297
Ring Documentation, Release 1.10 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) 36.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") 36.5 Remove() Function We can delete a file using the Remove() function Syntax: Remove(cFileName) Example: remove("test.txt") 36.6 Fopen() Function We can open a file using the Fopen() function Syntax: Fopen(cFileName,cMode) ---> File Handle 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 36.4. Rename() Function 298
Ring Documentation, Release 1.10 36.7 Fclose() Function When we open a file using fopen() function, we can close it using the Fclose() function Syntax: Fclose(file handle) 36.8 Fflush() Function We can flushes the output buffer of a stream using the Fflush() function Syntax: Fflush(file handle) 36.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: # Output to stdout Done # Output to file : myprogoutput.txt welcome 1 2 3 4 5 6 7 36.7. Fclose() Function 299
Ring Documentation, Release 1.10 8 9 10 36.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 36.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 36.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 36.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 36.10. Tempfile() Function 300
Ring Documentation, Release 1.10 36.14 Rewind() Function We can set the file position to the beginning of the file using the Rewind() function Syntax: Rewind(file handle) 36.15 Fgetpos() Function We can get handle to the current file position using the Fgetpos() function Syntax: Fgetpos(file handle) ---> position handle 36.16 Fsetpos() Function We can set the current file position using the Fgetpos() function Syntax: Fsetpos(file handle,position handle) 36.17 Clearerr() Function We can clear the EOF error and the error indicators of a stream using the clearerr() function Syntax: Clearerr(file handle) 36.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 36.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 36.14. Rewind() Function 301
Ring Documentation, Release 1.10 36.20 Perror() Function We can print error message to the stderr using the Perror() function Syntax: Perror(cErrorMessage) 36.21 Fgetc() Function We can get the next character from the stream using the Fgetc() function Syntax: Fgetc(file handle) ---> returns character or EOF 36.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. 36.23 Fputc() Function We can write a character to the stream using the Fputc() function Syntax: Fputc(file handle,cChar) 36.24 Fputs() Function We can write a string to the stream using the Fputs() function Syntax: Fputs(file handle,cString) 36.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: 36.20. Perror() Function 302
Ring Documentation, Release 1.10 Ungetc(file handle,character) 36.26 Fread() Function We can read data from a stream using the Fread() function Syntax: Fread(file handle,nSize) 36.27 Fwrite() Function We can write data to a stream using the Fwrite() function Syntax: Fwrite(file handle,cString) 36.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 36.29 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 36.26. Fread() Function 303
Ring Documentation, Release 1.10 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") 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 36.29. Example 304
Ring Documentation, Release 1.10 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) 36.30 Numbers and Bytes The next functions to convert between Numbers and Bytes. • Int2Bytes() • Float2Bytes() • Double2Bytes() • Bytes2Int() • Bytes2Float() • Bytes2Double() Example: 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 36.30. Numbers and Bytes 305
CHAPTER THIRTYSEVEN SYSTEM FUNCTIONS In this chapter we are going to learn about the system functions • System() • SysGet() • IsMSDOS() • IsWindows() • IsWindows64() • IsUnix() • IsMacOSX() • IsLinux() • IsFreeBSD() • IsAndroid() • Windowsnl() • Get Command Line Arguments • Get Active Source File Name • CurrentDir() • ExeFileName() • ChDir() • ExeFolder() • Version() • Shutdown() 37.1 System() Function We can execute system commands using the system() function Syntax: System(cCommand) Example: 306
Ring Documentation, Release 1.10 System("myapp.exe") # Run myapp.exe System("ls") # print list of files 37.2 SysGet() Function We can get environment variables using the Get() function Syntax: SysGet(cVariable) Example: see sysget("path") # print system path information 37.3 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 37.4 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 37.5 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 37.6 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 37.2. SysGet() Function 307
Ring Documentation, Release 1.10 37.7 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 37.8 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 37.9 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 37.10 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 37.11 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 37.7. IsMacOSX() Function 308
Ring Documentation, Release 1.10 IsLinux() --> 0 IsFreeBSD() --> 0 IsAndroid() --> 0 37.12 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) 37.13 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 37.12. Windowsnl() Function 309
Ring Documentation, Release 1.10 Size : 4 ring testssyspara.ring 1 10 ============================== 1 2 3 4 5 6 7 8 9 10 37.14 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: 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 37.15 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. 37.14. Get Active Source File Name 310
Ring Documentation, Release 1.10 Func IsMainSourceFile if PrevFileName() = sysargv[2] return true ok return false 37.16 CurrentDir() Function Return the path of the current directory Syntax: CurrenDir() ---> String contains the path of the currect directory 37.17 ExeFileName() Function Return the Ring executable file name Syntax: exefilename() ---> String contains the Ring executable file name 37.18 ChDir() Function Change the current directory Syntax: ChDir(cNewPath) 37.19 ExeFolder() Function Return the Ring executable file path Syntax: exefolder() ---> String contains the Ring executable path 37.20 Version() Function Return the Ring version Syntax: version() ---> String contains the Ring version Output: 37.16. CurrentDir() Function 311
Ring Documentation, Release 1.10 1.10 37.21 Shutdown() Function Close the application Syntax: shutdown(nStatus) ---> Close the application 37.21. Shutdown() Function 312
CHAPTER THIRTYEIGHT EVAL() AND DEBUGGING In this chapter we are going to learn about • Error Handling using Try/Catch/Done • Eval() function • Raise() function • Assert() function 38.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) : Cann't divide by zero ! 38.2 Eval() Function We can execute code during the runtime from string using the Eval() function Syntax: 313
Ring Documentation, Release 1.10 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 38.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: 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 38.3. Raise() Function 314
Ring Documentation, Release 1.10 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 38.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 38.4. Assert() Function 315
CHAPTER THIRTYNINE DEMO PROGRAMS In this chapter we will see simple demo programs • Language Shell • Main Menu 39.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 316
Ring Documentation, Release 1.10 39.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 39.2. Main Menu 317
Ring Documentation, Release 1.10 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 =========== [1] Say Hello [2] Sum two numbers 39.2. Main Menu 318
Ring Documentation, Release 1.10 [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 39.2. Main Menu 319
CHAPTER FORTY ODBC FUNCTIONS This chapter contains 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 40.1 odbc_init() Function We can create ODBC Handle using the odbc_init() function Syntax: odbc_init() ---> ODBC Handle 320
Ring Documentation, Release 1.10 40.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 40.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 40.4 odbc_close() Function After the end of using ODBC functions we can free resources using ODBC_Close() function Syntax: odbc_close(ODBC Handle) 40.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 Microsoft Excel-Treiber (*.xls) - SQLLevel=0 Microsoft Access Driver (*.mdb) - SQLLevel=0 Driver do Microsoft Access (*.mdb) - SQLLevel=0 40.2. odbc_drivers() Function 321
Ring Documentation, Release 1.10 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 40.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 Visual FoxPro Database - Microsoft Visual FoxPro Driver Visual FoxPro Tables - Microsoft Visual FoxPro Driver 40.6. Print List of ODBC Data Sources 322
Ring Documentation, Release 1.10 40.7 odbc_connect() Function We can connect to the database using the odbc_connect() function. Syntax: odbc_connect(ODBC Handle, cConnectionString) 40.8 odbc_disconnect() Function We can close the connection to the database using the odbc_disconnect() function. Syntax: odbc_disconnect(ODBC Handle) 40.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... 40.10 odbc_execute() Function We can execute SQL Statements on the database using the odbc_execute() function. Syntax: odbc_execute(ODBC Handle, cSQLStatement) 40.11 odbc_colcount() Function We can get columns count in the query result using the odbc_colcount() function. Syntax: 40.7. odbc_connect() Function 323
Ring Documentation, Release 1.10 odbc_colcount(ODBC Handle) ---> Columns Count as Number 40.12 odbc_fetch() Function We can fetch a row from the query result using the odbc_fetch() function. Syntax: odbc_fetch(ODBC Handle) 40.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 40.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) + " - " next end See "Close database..." + nl odbc_disconnect(pODBC) odbc_close(pODBC) 40.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: 40.12. odbc_fetch() Function 324
Ring Documentation, Release 1.10 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... 40.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: 40.16. odbc_columns() Function 325
Ring Documentation, Release 1.10 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... 40.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 40.18 odbc_commit() Function We can commit updates to the database using the odbc_commit() function. Syntax: odbc_commit(ODBC Handle) 40.19 odbc_rollback() Function We can rollback updates to the database using the odbc_rollback() function. Syntax: odbc_rollback(ODBC Handle) 40.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) 40.17. odbc_autocommit() Function 326
Ring Documentation, Release 1.10 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... 40.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) 40.21. Save and Restore images 327
Ring Documentation, Release 1.10 See "Write image file" + nl write("testsgreat.jpg",hex2str( odbc_getdata(pODBC,3) ) ) ok See "Close database..." + nl odbc_disconnect(pODBC) odbc_close(pODBC) 40.21. Save and Restore images 328
CHAPTER FORTYONE MYSQL FUNCTIONS In this chapter 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 41.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: see "MySQL Client Version : " + mysql_info() 329
Ring Documentation, Release 1.10 Output: MySQL Client Version : 6.1.5 41.2 MySQL_Init() Function We can start using MySQL Client through the MySQL_Init() function. Syntax: MySQL_Init() ---> MySQL Handle 41.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 41.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 41.5 MySQL_Close() Function We can close the connection to the MySQL database using the MySQL_Close() function Syntax: MySQL_Close(MySQL Handle) 41.6 MySQL_Query() Function We can execute SQL queries using the MySQL_Query() function Syntax: MySQL_Query(MySQL Handle, cSQLQuery) 41.2. MySQL_Init() Function 330
Ring Documentation, Release 1.10 41.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 "Cann'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 41.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 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)") 41.7. Create Database 331
Ring Documentation, Release 1.10 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 41.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 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 41.9. MySQL_Insert_ID() Function 332
Ring Documentation, Release 1.10 41.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 41.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) 41.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) see "close database" + nl mysql_close(con) Output: Connect to database Execute Query Print Result Mahmoud Fayed close database 41.13 MySQL_Columns() Function We can get a list of columns names using the MySQL_Columns() function. Syntax: 41.10. MySQL_Result() Function 333
Ring Documentation, Release 1.10 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 41.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: 41.14. MySQL_Result2() Function 334
Ring Documentation, Release 1.10 Connect to database Execute Query Print Result Id Name Salary 1 Mahmoud 15000 2 Samir 16000 3 Fayed 17000 Close database 41.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 41.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... 41.15. MySQL_Escape_String() Function 335
Ring Documentation, Release 1.10 41.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... 41.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 41.19 MySQL_Commit() Function We can commit updates to the database using the MySQL_Commit() function. Syntax: MySQL_Commit(MySQL Handle) 41.20 MySQL_Rollback() Function We can rollback updates to the database using the MySQL_Rollback() function. Syntax: MySQL_Rollback(MySQL Handle) 41.21 Transaction Example The next example presents the usage of MySQL_Autocommit(), MySQL_Commit() & MySQL_RollBack() functions. Example: 41.17. Restore Image From The Database 336
Ring Documentation, Release 1.10 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)") 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 41.21. Transaction Example 337
CHAPTER FORTYTWO SQLITE FUNCTIONS In this chapter 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 42.1 sqlite_init() function Syntax: sqlite_init() ---> SQLite Object 42.2 sqlite_open() function Syntax: sqlite_open(SQLite Object,cFileName) 42.3 sqlite_execute() function Syntax: sqlite_execute(SQLite Object,cSQLStatement) 42.4 sqlite_close() function Syntax: sqlite_close(SQLite Object) 338
Ring Documentation, Release 1.10 42.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 Egypt 42.5. Example 339
Ring Documentation, Release 1.10 20000.0 4 Ibrahim 24 Egypt 65000.0 ************************************************** Mahmoud Ahmed Mohammed Ibrahim 42.5. Example 340
CHAPTER FORTYTHREE POSTGRESQL FUNCTIONS In this chapter we will learn about using the PostgreSQL database in the Ring programming language. 43.1 Loading the library Before using the next function load the postgresqllib.ring library load "postgresqllib.ring" # Use PostgreSQL functions 43.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) next 341
Ring Documentation, Release 1.10 ? 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 res = PQexec(conn, " DROP DATABASE mahdb; 43.2. Examples 342
Ring Documentation, Release 1.10 ") 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 ? PQfname(res, i-1) next ? copy("*",60) 43.2. Examples 343
Ring Documentation, Release 1.10 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 43.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 PGRES_COPY_BOTH PGRES_SINGLE_TUPLE PG_DIAG_SEVERITY PG_DIAG_SQLSTATE PG_DIAG_MESSAGE_PRIMARY PG_DIAG_MESSAGE_DETAIL 43.3. RingPostgreSQL Constants 344
Ring Documentation, Release 1.10 PG_DIAG_MESSAGE_HINT PG_DIAG_STATEMENT_POSITION PG_DIAG_INTERNAL_POSITION PG_DIAG_INTERNAL_QUERY PG_DIAG_CONTEXT PG_DIAG_SCHEMA_NAME PG_DIAG_TABLE_NAME PG_DIAG_COLUMN_NAME PG_DIAG_DATATYPE_NAME PG_DIAG_CONSTRAINT_NAME PG_DIAG_SOURCE_FILE PG_DIAG_SOURCE_LINE PG_DIAG_SOURCE_FUNCTION 43.4 RingPostgreSQL Functions The next functions are define by the RingPostgreSQL Library Reference : https://www.postgresql.org/docs/9.1/static/libpq.html PGconn *PQconnectdbParams(const char **keywords, const char **values,int expand_dbname); PGconn *PQconnectdb(const char *conninfo) PGconn *PQsetdbLogin(const char *pghost,const char *pgport, const char *pgoptions,const char *pgtty, const char *dbName,const char *login,const char *pwd) PGconn *PQsetdb(char *pghost,char *pgport,char *pgoptions, char *pgtty,char *dbName) PGconn *PQconnectStartParams(const char **keywords, const char **values,int expand_dbname) PGconn *PQconnectStart(const char *conninfo) PostgresPollingStatusType PQconnectPoll(PGconn *conn) PQconninfoOption *PQconndefaults(void) PQconninfoOption *PQconninfo(PGconn *conn) PQconninfoOption *PQconninfoParse(const char *conninfo, char **errmsg) void PQfinish(PGconn *conn) void PQreset(PGconn *conn) int PQresetStart(PGconn *conn) PostgresPollingStatusType PQresetPoll(PGconn *conn) PGPing PQpingParams(const char **keywords,const char **values, int expand_dbname) PGPing PQping(const char *conninfo) char *PQdb(const PGconn *conn) char *PQuser(const PGconn *conn) char *PQpass(const PGconn *conn) char *PQhost(const PGconn *conn) char *PQport(const PGconn *conn) 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) 43.4. RingPostgreSQL Functions 345
Ring Documentation, Release 1.10 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, 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, 43.4. RingPostgreSQL Functions 346
Ring Documentation, Release 1.10 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) 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) 43.4. RingPostgreSQL Functions 347
CHAPTER FORTYFOUR SECURITY AND INTERNET FUNCTIONS This chapter contains the security and internet functions provided by the Ring programming language for Hashing, Encryption & Decryption. Before using the next function load the openssllib.ring library load "openssllib.ring" # Use OpenSSL functions • MD5() • SHA1() • SHA256() • SHA512() • SHA384() • SHA224() • Encrypt() • Decrypt() • Randbytes() Before using the next function load the internetlib.ring library load "internetlib.ring" # Use the Internet functions • Download() • SendEmail() 44.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 348
Ring Documentation, Release 1.10 Output: md5('happy') = 56ab24c15b72a457069c5ea42fcfc640 md5('Hello') = 8b1a9953c4611296a827abf8c47804d7 44.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 44.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 44.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 44.2. SHA1() Function 349
Ring Documentation, Release 1.10 Output: sha512('hello') : 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673c a72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043 sha512('apple') : 844d8779103b94c18f4aa4cc0c3b4474058580a991fba85d3ca698a0bc9e52 c5940feb7a65a3a290e17e6b23ee943ecc4f73e7490327245b4fe5d5efb590feb2 sha512('hello world') : 309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca8 6d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f 44.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 44.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 44.7 Encrypt() Function We can use the Encrypt() function to encrypts the data using the Blowfish algorithm. 44.5. SHA384() Function 350
Ring Documentation, Release 1.10 Syntax: Encrypt(cString, cKey, cIV) ---> Encrypted string 44.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 44.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 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 44.8. Decrypt() Function 351
Ring Documentation, Release 1.10 44.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 44.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 44.12 Download() Function Syntax: Download(cURL) ---> String contains the server response Example: cStr= download("http://doublesvsoop.sourceforge.net/") see cStr write("download.txt",cStr) 44.10. File Hash 352
Ring Documentation, Release 1.10 44.13 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 44.13. SendEmail() Function 353
CHAPTER FORTYFIVE 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() 45.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] ] 354
Ring Documentation, Release 1.10 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 new point { print() } Class Point x = 10 y = 20 z = 30 func print see x + nl + y + nl + z + nl 45.1. Classes and Objects 355
Ring Documentation, Release 1.10 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. 45.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 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 + 45.2. Access Objects Using Braces 356
Ring Documentation, Release 1.10 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 45.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 + "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: 45.3. Composition 357
Ring Documentation, Release 1.10 Name : Rectangle 1 Color: Blue P1 : (10,20) P2 : (200,300) 45.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: Message from SetName() Function! Message from GetName() Function! Mr. Mahmoud Fayed Message from SetName() Function! Message from GetName() Function! Mr. Ahmed Fayed 45.5 Private Attributes and Methods We can define private attributes and methods after the keyword private inside the class body 45.4. Setter and Getter 358
Ring Documentation, Release 1.10 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 Error (R27) : Using private attribute from outside the class : salary Error (R26) : Calling private method from outside the class : increasesalary 45.6 Operator Overloading We can add the operator method to our class to enable using operators with the class objects. Syntax: Class ClassName ... 45.6. Operator Overloading 359
Ring Documentation, Release 1.10 Func operator cOperator,Para ... The function operator takes two paramters, the first represent the operator and the second represent the second param- eter 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 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 45.6. Operator Overloading 360
Ring Documentation, Release 1.10 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" ### 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 45.6. Operator Overloading 361
Ring Documentation, Release 1.10 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 45.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 ... 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 45.7. Inheritance 362
Ring Documentation, Release 1.10 super.print() see "Job : " + job + nl + "Salary : " + salary + nl Output: Name : test Age : 20 Job : programmer Salary : 20000000 45.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! Note: we can write class definitions inside a string then using eval() we can execute the string to define the classes 45.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 45.8. Dynamic Attributes 363
Ring Documentation, Release 1.10 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 45.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 45.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 45.10. Printing Objects 364
Ring Documentation, Release 1.10 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 Other 0 0 0 45.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 45.12. Sort() and List of Objects 365
Ring Documentation, Release 1.10 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 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 45.12. Sort() and List of Objects 366
Ring Documentation, Release 1.10 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 45.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 Whay 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 45.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. 45.13. Using Self.Attribute and Self.Method() 367
Ring Documentation, Release 1.10 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 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 45.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. 45.15. Using This in the class region as Self 368
Ring Documentation, Release 1.10 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 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. 45.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 45.16. Default value for object attributes 369
CHAPTER FORTYSIX FUNCTIONAL PROGRAMMING In previous chapters 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 46.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 5 370
Ring Documentation, Release 1.10 aList2 1 4 9 16 25 46.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! 46.3 Higher-order Functions Higher-order functions are the functions that takes other functions as parameters. Example: Func Main times(5,:test) 46.2. First-class Functions 371
Ring Documentation, Release 1.10 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! 46.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 Class great func f1 f2( func { see "Message from f1" + nl } ) func f2 x call x() Output: hello Sum : 6 46.4. Anonymous and Nested Functions 372
Ring Documentation, Release 1.10 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 True False False odd even odd even 46.5 Equality of functions We can test if function = function or not using the ‘=’ or ‘!=’ operators 46.5. Equality of functions 373
Ring Documentation, Release 1.10 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 46.5. Equality of functions 374
CHAPTER FORTYSEVEN REFLECTION AND META-PROGRAMMING Since the 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() 375
Ring Documentation, Release 1.10 • getattribute() • setattribute() • mergemethods() • packagename() 47.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 47.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() Output: 47.1. locals() Function 376
Ring Documentation, Release 1.10 message from test() Global Variables: x y z 47.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 47.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: Count : 208 len() add() del() get() 47.3. functions() Function 377
Ring Documentation, Release 1.10 clock() ... Note: The complete list is removed from the previous output. 47.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 47.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() func test see isglobal("x") + nl + isglobal("y") + nl + isglobal("z") + nl Output: 1 1 0 47.5. islocal() Function 378
Ring Documentation, Release 1.10 47.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 47.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 Output: 1 1 0 47.9 packages() Function We can get a list of packages names using the packages() function. Syntax: packages() --> a list contains packages names 47.7. isfunction() Function 379
Ring Documentation, Release 1.10 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 47.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: 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 47.10. ispackage() Function 380
Ring Documentation, Release 1.10 Output: 1 1 0 1 47.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 47.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 47.11. classes() Function 381
Ring Documentation, Release 1.10 Output: 0 1 1 47.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 Output: classes in Package1 class1 classes in Package2 class1 class2 class3 47.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 + 47.13. packageclasses() Function 382
Ring Documentation, Release 1.10 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 47.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: o1 = new point o2 = new rect see classname(o1) + nl # print point see classname(o2) + nl # print rect class point class rect 47.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 47.15. classname() Function 383
Ring Documentation, Release 1.10 Class point x y z Output: 021B5808 021B5808 47.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 47.18 attributes() Function We can get the object attributes using the attributes() function Syntax: attributes(object) --> Returns a list contains the object attributes Example: 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 47.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 47.17. isobject() Function 384
Ring Documentation, Release 1.10 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 47.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: 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 47.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 47.20. isattribute() Function 385
Ring Documentation, Release 1.10 Output: 0 0 0 1 1 47.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: 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 47.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: 47.22. ismethod() Function 386
Ring Documentation, Release 1.10 0 1 47.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): 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 47.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: 47.24. addattribute() Function 387
Ring Documentation, Release 1.10 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 ) 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 47.25. addmethod() Function 388
Ring Documentation, Release 1.10 50 150 250 47.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 47.26. getattribute() function 389
Ring Documentation, Release 1.10 See nl + "FindClass: " +" "+ cValue + nl + nl for i = 1 to len(classList) result = getattribute( classList[i], classMember ) 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 47.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 47.27. setattribute() function 390
Ring Documentation, Release 1.10 acolors: List... white blue yellow 47.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 ******************** 47.28. mergemethods() Function 391
Ring Documentation, Release 1.10 three two one ******************** 47.29 packagename() Function We can know the package name of the latest sucessful import command using the packagename() function Syntax: packagename() --> Returns the package name of the latest sucessful import Example: load "weblib.ring" import System.web see packagename() # system.web 47.29. packagename() Function 392
CHAPTER FORTYEIGHT STDLIB FUNCTIONS In this chapter 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. 48.1 Puts() function print the value then print new line (nl) Syntax: puts(expr) Example: Load "stdlib.ring" Puts("Hello, World!") 48.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: print("nHello, WorldnnHow are you? tt I'm fine!n") x=10 y=20 print("nx value = #{x} , y value = #{y} n") 393
Ring Documentation, Release 1.10 48.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 48.4 GetString() function Get input from the keyboard - return value as string getstring() ---> string 48.5 GetNumber() function Get input from the keyboard - return value as number getnumber() ---> number 48.6 AppPath() function Get the path of the application folder Syntax: AppPath() ---> The path as String Example: Load "stdlib.ring" # Application Path Puts("Test AppPath()") See AppPath() + nl 48.7 JustFilePath() function Get the path of the file, remove the file name. 48.3. Print2Str() Function 394
Ring Documentation, Release 1.10 Syntax: JustFilePath(cFile) ---> The path as String Example: load "stdlib.ring" see justfilePath("b:ringapplicationsrnoternote.ring") Output: b:ringapplicationsrnote 48.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 48.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 48.10 Times() function Execute a Function nCount times Syntax: 48.8. JustFileName() function 395
Ring Documentation, Release 1.10 Times(nCount,function) Example: Load "stdlib.ring" Puts("Test Times()") Times ( 3 , func { see "Hello, World!" + nl } ) 48.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 } ) 48.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 } ) 48.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"," ") 48.11. Map() function 396
Ring Documentation, Release 1.10 48.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"," ,") 48.15 NewList() function Create a two dimensional list Syntax: NewList(nRows,nColumns) ---> new list Example: Load "stdlib.ring" Puts("Test Newlist()") a1 = 3 a2 = 5 chrArray = newlist(a1,a2) numArray = newlist(a1,a2) chrArray[1][1] = "Hello" numArray[1][1] = 987.2 See chrArray[1][1] + nl See numArray[1][1] + nl 48.16 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") 48.14. SplitMany() function 397
Ring Documentation, Release 1.10 48.17 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 48.18 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 48.19 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") 48.20 Factorial() function Return the factorial of a number Syntax: Factorial(number) ---> number Example: 48.17. IsSpecial() function 398
Ring Documentation, Release 1.10 Load "stdlib.ring" Puts("Test Factorial()") see "6 factorial is : " + Factorial(6) 48.21 Fibonacci() function Return the fibonacci number Syntax: Fibonacci(number) ---> number Example: Load "stdlib.ring" Puts("Test Fibonacci()") see "6 Fibonacci is : " + Fibonacci(6) 48.22 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 48.23 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 48.21. Fibonacci() function 399
Ring Documentation, Release 1.10 48.24 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") 48.25 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")) 48.26 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 48.27 EndsWith() function Returns true if the given string ends with the specified substring. Trailing white spaces are ignored. 48.24. List2File() function 400
Ring Documentation, Release 1.10 Syntax: Endswith(string, substring) ---> True/False Example: Load "stdlib.ring" Puts("Test Endswith()") see endsWith("CalmoSoft", "Soft") + nl 48.28 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 48.29 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 48.30 SumList() function Compute the sum of a list of integers. Syntax: sumlist(list) ---> number Example: Load "stdlib.ring" Puts("Test Sumlist()") 48.28. GCD() function 401
Ring Documentation, Release 1.10 aList = [1,2,3,4,5] see Sumlist(aList) + nl 48.31 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 48.32 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 48.33 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) 48.31. ProdList() function 402
Ring Documentation, Release 1.10 see "" + aList[i] + " " next 48.34 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) 48.35 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 48.36 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) 48.34. IsPalindrome() function 403
Ring Documentation, Release 1.10 48.37 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) 48.38 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) 48.39 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 48.37. MatrixMulti() function 404
Ring Documentation, Release 1.10 48.40 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 48.41 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) 48.42 SubString() function Return a position of a substring starting from a given position in a string. Syntax: Substring(str,substr,npos) ---> string Example: Load "stdlib.ring" # Return a position of a substring starting from a given position in a string. 48.40. Permutation() function 405
Ring Documentation, Release 1.10 Puts("Test Substring()") a = "abcxyzqweabc" b = "abc" i = 4 see substring(a,b,i) 48.43 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 48.44 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 48.45 IsMainSourceFile() function Check if the current file is the main source file Syntax: IsMainSourceFile() ---> True/False Example: Load "stdlib.ring" if ismainsourcefile() # code ok 48.43. ChangeString() function 406
Ring Documentation, Release 1.10 48.46 DirExists() function Check if directory exists Syntax: DirExists(String) ---> True/False Example: Load "stdlib.ring" see "Check dir : b:ring " puts( DirExists("b:ring") ) see "Check dir : C:ring " Puts( DirExists("C:ring") ) 48.47 MakeDir() function Make Directory Syntax: MakeDir(String) Example: Load "stdlib.ring" # Create Directory puts("create Directory : myfolder") makedir("myfolder") 48.48 Fsize() function The function return the file size in bytes. Syntax: FSize(File Handle) ---> Number (File Size in Bytes) 48.49 TrimAll() function Remove all spaces and tabs characters from a string Syntax: TrimAll(cString) ---> cString # Without Spaces and Tabs 48.46. DirExists() function 407
Ring Documentation, Release 1.10 48.50 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 48.51 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 48.52 EpochTime() function Return the Epoch Time Syntax: EpochTime(cDate,cTime) ---> nEpochTime Example: see EpochTime( Date(), Time() ) 48.53 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 48.54 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: 48.50. TrimLeft() function 408
Ring Documentation, Release 1.10 aList = ListAllFiles("c:/ring/ringlibs","ring") # *.ring only aList = sort(aList) see aList Example: see listallfiles("b:/ring/ringlibs/weblib","") # All Files 48.55 SystemSilent() Function We can execute system commands using the SystemSilent() function to avoid displaying the output! Syntax: SystemSilent(cCommand) 48.56 OSCreateOpenFolder() Function Create folder then change the current folder to this new folder Syntax: OSCreateOpenFolder(cCommand) 48.57 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") 48.58 OSDeleteFolder() Function Delete Folder in the current Directory Syntax: OSDeleteFolder(cFolderName) 48.55. SystemSilent() Function 409
Ring Documentation, Release 1.10 48.59 OSCopyFile() Function Copy File to the current directory Syntax: OSCopyFile(cFileName) 48.60 OSDeleteFile() Function Delete File Syntax: OSDeleteFile(cFileName) 48.61 OSRenameFile() Function Rename File Syntax: OSRenameFile(cOldFileName,cNewFileName) 48.62 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 ] 48.63 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 48.59. OSCopyFile() Function 410
Ring Documentation, Release 1.10 48.64 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 48.64. ASCIIList2Str() 411
CHAPTER FORTYNINE STDLIB CLASSES In this chapter 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 49.1 StdBase Class Attributes: • vValue : Object Value 412
Ring Documentation, Release 1.10 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) 49.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() 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 49.2. String Class 413
Ring Documentation, Release 1.10 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 1 -1 one two three 4 1234 List Items one two three the - position : 12 49.2. String Class 414
Ring Documentation, Release 1.10 Ring programming language Ring ***Ring*** programming language ******Ring****** programming language FirstSecond FirstFirstFirst FirstFirstFirst one two three Hello How are you? 49.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 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" ] ) 49.3. List Class 415
Ring Documentation, Release 1.10 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 two 3 three Search two : 2 Search 1 : 1 Egypt USA KSA 1 2 3 4 5 6 7 one two 49.3. List Class 416
Ring Documentation, Release 1.10 three four 49.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 4 three two one 49.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 49.4. Stack Class 417
Ring Documentation, Release 1.10 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 49.6 HashTable Class Parent Class : List Class Methods: 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: 49.6. HashTable Class 418
Ring Documentation, Release 1.10 Test the hashtable Class Methods Cairo Riyadh 1 0 2 Egypt Cairo KSA Riyadh ************************************************************ Egypt Cairo 49.7 Tree Class Data: Attribute Description Data Node Value Children Children List Methods: 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") } 49.7. Tree Class 419
Ring Documentation, Release 1.10 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... 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 49.8 Math Class Methods: 49.8. Math Class 420
Ring Documentation, Release 1.10 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 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 49.8. Math Class 421
Ring Documentation, Release 1.10 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 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 49.8. Math Class 422
Ring Documentation, Release 1.10 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 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 49.8. Math Class 423
Ring Documentation, Release 1.10 49.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 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 49.9. DateTime Class 424
Ring Documentation, Release 1.10 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 49.10 File Class Methods: 49.10. File Class 425
Ring Documentation, Release 1.10 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() 49.11 System Class Methods: 49.11. System Class 426
Ring Documentation, Release 1.10 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 49.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: 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) 49.12. Debug Class 427
Ring Documentation, Release 1.10 catch see "assert" + nl done raise("Error!") 49.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 hexdecimal 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 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 49.13. DataType Class 428
Ring Documentation, Release 1.10 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 49.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" 49.14. Conversion Class 429
Ring Documentation, Release 1.10 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 49.15 ODBC Class Methods: 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 49.15. ODBC Class 430
Ring Documentation, Release 1.10 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() } 49.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 49.16. MySQL Class 431
Ring Documentation, Release 1.10 Execute Query Print Result Id Name Salary 1 Mahmoud 15000 2 Samir 16000 3 Fayed 17000 Close database 49.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 49.17. SQLite Class 432
Ring Documentation, Release 1.10 see t[2] + nl next next see copy("*",50) + nl for x in aResult see x["name"] + nl next close() } 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 49.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 { 49.18. PostgreSQL Class 433
Ring Documentation, Release 1.10 sql = "CREATE TABLE COMPANY_TEST(" + "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_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 ************************************************** 49.18. PostgreSQL Class 434
Ring Documentation, Release 1.10 49.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 } 49.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") } 49.19. Security Class 435
CHAPTER FIFTY DECLARATIVE PROGRAMMING USING NESTED 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 50.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: Item 4 is a list contains 3 items 1 2 436
Ring Documentation, Release 1.10 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 50.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 x: 100.000000 y: 200.000000 z: 300.000000 Example(2): 50.2. Composition and Returning Objects and Lists by Reference 437
Ring Documentation, Release 1.10 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 } } 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 50.2. Composition and Returning Objects and Lists by Reference 438
Ring Documentation, Release 1.10 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 50.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! 50.4 Declarative Programming on the top of Object-Oriented The next features enable us to build and use declartive 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: # Declartive Programming (Nested Structures) Screen() { point() { x = 100 y = 200 z = 300 } 50.3. Executing code after the end of object access 439
Ring Documentation, Release 1.10 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! 50.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 direcly 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 { 50.5. More beautiful Code 440
Ring Documentation, Release 1.10 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 50.5. More beautiful Code 441
CHAPTER FIFTYONE NATURAL LANGUAGE PROGRAMMING Using the Ring programming language, we can create Natural programming languages based on classes and objects. 51.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. 51.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 442
Ring Documentation, Release 1.10 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 51.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 { I want window and the window title = "hello world" } Class App 51.3. Change the Ring Keyword ‘And’ 443
Ring Documentation, Release 1.10 # 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 51.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: 51.4. Change the Ring Operator ‘+’ 444
Ring Documentation, Release 1.10 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 51.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 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 51.5. Change the ‘=’ operator to ‘is’ 445
Ring Documentation, Release 1.10 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 51.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 ' + 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 51.6. Using Eval() with our Natural Code 446
Ring Documentation, Release 1.10 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 51.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: 51.7. BraceStart and BraceEnd Methods 447
Ring Documentation, Release 1.10 start Hello end start end 51.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 51.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 51.8. BraceExprEval Method 448
Ring Documentation, Release 1.10 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 51.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") 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 } 51.10. BraceError() Method 449
Ring Documentation, Release 1.10 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... 51.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 { 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 51.11. Clean Natural Code 450
Ring Documentation, Release 1.10 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,":") while c > 0 c= substr(cCatchError,":") cCatchError=substr(cCatchError,c+1) end literal += substr(cCatchError,1) 51.11. Clean Natural Code 451
CHAPTER FIFTYTWO USING THE NATURAL LIBRARY 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) 52.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. 452
Ring Documentation, Release 1.10 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) RunFile("program.txt") } We defined a language called MyLanguage, We have folder for the language commands. 52.1. Natural Library - Demo Program 453
Ring Documentation, Release 1.10 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) } ]) 52.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) 52.2. Defining Commands 454
Ring Documentation, Release 1.10 • 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. 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) } ]) 52.2. Defining Commands 455
Ring Documentation, Release 1.10 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 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 52.2. Defining Commands 456
Ring Documentation, Release 1.10 52.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! ") } 52.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 52.3. Natural Library - Operators 457
Ring Documentation, Release 1.10 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 } 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) 52.4. Defining commands using classes 458
CHAPTER FIFTYTHREE WEB DEVELOPMENT (CGI LIBRARY) In this chapter we will learn about developing Web applications using a CGI Library written in the Ring language. 53.1 Configure the Apache web server We can use Ring with any web server that support CGI. In this section we will learn about using Ring with the Apache HTTP Server. You can download Apache from : http://httpd.apache.org/ Or you can get it included with other projects like XAMPP : https://www.apachefriends.org/download.html Install then open the file: xamppapacheconfhttpd.conf search for <Directory /> Then after it add Options FollowSymLinks +ExecCGI So we have <Directory /> Options FollowSymLinks +ExecCGI Search for the next line and be 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 AddHandler cgi-script .cgi .ring Example AddHandler cgi-script .cgi .pl .asp .ring 459
Ring Documentation, Release 1.10 Run/Start the server Create your web applications in a directory supported by the web server. Example: Apache2.2htdocsmywebapplicationfolder Example: xampphtdocsmywebapplicationfolder Inside the source code file (*.ring), Add this line #!ring -cgi Note: Change the previous line based on the path to ring.exe in your machine 53.2 Ring CGI Hello World Program The next program is the Hello World program #!ring -cgi See "content-type: text/html" +nl+nl+ "Hello World!" + nl 53.3 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!") } Example (2) : #!ring -cgi Load "weblib.ring" Import System.Web WebPage() { Text("Hello World!") } 53.2. Ring CGI Hello World Program 460
Ring Documentation, Release 1.10 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. 53.4 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 53.5 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) ]) divstart([:style = stylefloatleft() + stylesize("100px","100%") + stylecolor("black") + stylegradient(58)]) formstart("ex5.ring") tablestart([ :style = stylesize("65%","90%") + stylemarginleft("35%") + stylemargintop("30%") ]) rowstart([]) cellstart([]) text ( "Name : " ) cellend() cellstart([]) cTextboxStyle = StyleMarginLeft("5%") + StyleWidth("250px") + StyleColor("black") + 53.4. Web Library Features 461
Ring Documentation, Release 1.10 StyleBackColor("white") textbox([ :name = "Name", :style = cTextboxStyle ] ) cellend() rowend() rowstart([]) cellstart([]) text ( "Address : " ) cellend() cellstart([]) textbox([ :name = "Address", :style = cTextboxStyle] ) cellend() rowend() rowstart([]) cellstart([]) text ( "Phone : " ) cellend() cellstart([]) textbox([ :name = "Phone", :style = cTextboxStyle ]) cellend() rowend() rowstart([]) cellstart([]) text ( "Age : " ) cellend() cellstart([]) textbox([ :name = "Age", :style = cTextboxStyle ]) cellend() rowend() rowstart([]) cellstart([]) text ( "City: " ) cellend() cellstart([]) listbox([ :name = "City", :items = ["Cairo","Riyadh","Jeddah"], :style = stylemarginleft("5%") + stylewidth("400px") ] ) cellend() rowend() rowstart([]) cellstart([]) text ( "Country : " ) cellend() cellstart([]) combobox([ :name = "Country", :items = ["Egypt","Saudi Arabia","USA"], :style = stylemarginleft("5%") + stylewidth("400px")+ stylecolor("black")+ stylebackcolor("white")+ stylefontsize("14px") ]) cellend() rowend() rowstart([]) cellstart([]) text ( "Note : " ) cellend() cellstart([]) editbox([ :name = "Notes", :style = stylemarginleft("5%") + 53.5. HTTP Get Example 462
Ring Documentation, Release 1.10 stylesize("400px","100px")+ stylecolor("black")+ stylebackcolor("white") , :value = "write comments here..." ] ) cellend() rowend() rowstart([]) cellstart([]) cellend() cellstart([]) submit([ :value = "Send" , :Style = stylemarginleft("5%") ]) cellend() rowend() tableend() formend() divend() divend() divend() } Screen Shot: 53.5. HTTP Get Example 463
Ring Documentation, Release 1.10 The Response #!ring -cgi Load "weblib.ring" Import System.Web New Page { divstart([ :style = styledivcenter("800px","500px") ]) boxstart() text ( "HTTP GET Response" ) newline() boxend() divstart([ :style = stylefloatleft()+stylewidth("10%")+ 53.5. HTTP Get Example 464
Ring Documentation, Release 1.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: 53.5. HTTP Get Example 465
Ring Documentation, Release 1.10 53.6 HTTP POST Example The Page User Interface #!ring -cgi Load "weblib.ring" Import System.Web New Page { boxstart() text( "Post Test") newline() boxend() divstart([ :style=StyleFloatLeft()+StyleWidth("100px") ]) newline() text( "Number1 : " ) newline() newline() text( "Number2 : " ) newline() newline() divend() formpost("ex7.ring") divstart([ :style = styleFloatLeft()+StyleWidth("200px") ]) newline() textbox([ :name = "Number1" ]) newline() newline() textbox([ :name = "Number2" ]) newline() newline() submit([ :value = "Send" ] ) divend() formend() } Screen Shot: 53.6. HTTP POST Example 466
Ring Documentation, Release 1.10 The Response #!ring -cgi Load "weblib.ring" Import System.Web New Page { boxstart() text( "Post Result" ) newline() boxend() divstart([ :style = styleFloatLeft()+styleWidth("200px") ]) newline() text( "Number1 : " + aPageVars["Number1"] ) newline() newline() text( "Number2 : " + aPageVars["Number2"] ) newline() newline() text( "Sum : " + (0 + aPageVars["Number1"] + aPageVars["Number2"] ) ) newline() divend() } Screen Shot: 53.6. HTTP POST Example 467
Ring Documentation, Release 1.10 53.7 Upload Files The Page User Interface #!ring -cgi Load "weblib.ring" Import System.Web New page { boxstart() text( "Upload File" ) newline() boxend() for x = 1 to 3 newline() next formupload("ex9.ring") text( "Customer Name : " ) textbox([ :name = "custname" ]) newline() newline() divstart([ :style = styleFloatLeft() + styleWidth("90px") ]) uploadfile("file") newline() newline() uploadfile("file2") newline() newline() submit([ :value = "Send" ]) divend() formend() } Screen Shot: 53.7. Upload Files 468
Ring Documentation, Release 1.10 The Response #!ring -cgi Load "weblib.ring" Import System.Web cUploadPath = "C:/Apache2.2/htdocs/ringapp/upload/" cUploadFolder = "/ringapp/upload/" New page { boxstart() text( "Upload Result" ) newline() boxend() newline() divstart([ :style= styleFloatLeft() + styleWidth("100px") ]) text( "Name : " + aPageVars["custname"] ) newline() divend() if aPageVars["file"] != char(13) getuploadedfile(self,"file") ok if aPageVars["file2"] != char(13) getuploadedfile(self,"file2") ok } Func getuploadedfile oObj,cFile # here we use object.property # instead of object { } to avoid executing braceend method cFileName = cUploadPath + oObj.getfilename(aPageVars,cFile) 53.7. Upload Files 469
Ring Documentation, Release 1.10 write(cFileName,aPageVars[cFile]) system("chmod a+x "+cFileName) oObj.newline() oObj.text( "File "+cFileName+ " Uploaded ..." ) oObj.newline() imageURL = cUploadFolder + oObj.getfilename(aPageVars,cFile) oObj.link([ :url = imageURL, :title = "Download" ]) oObj.newline() oObj.image( [ :url = imageURL , :alt = :image ] ) oObj.newline() Screen Shot: 53.7. Upload Files 470
Ring Documentation, Release 1.10 53.8 Cookies The Page User Interface #!ring -cgi Load "weblib.ring" 53.8. Cookies 471
Ring Documentation, Release 1.10 Import System.Web New page { boxstart() text( "Cookie Test" ) newline() boxend() newline() link([ :url = "ex11.ring", :title = "Use Cookies" ]) cookie("custname","Mahmoud Fayed") cookie("custage",28) } Screen Shot: The Response #!ring -cgi Load "weblib.ring" Import System.Web New Page { boxstart() text( "Cookies Values" ) newline() boxend() link([ :url = "ex10.ring", :title = "back" ]) newline() divstart([:style="float:left;width:200px"]) text( "Name : " + aPageVars["custname"] ) newline() text( "Age : " + aPageVars["custage"] ) newline() divend() } Screen Shot: 53.8. Cookies 472
Ring Documentation, Release 1.10 53.9 URL Encode The Page User Interface #!ring -cgi Load "weblib.ring" Import System.Web New Page { boxstart() text( "URLEncode" ) newline() boxend() link([ :url = "ex5.ring?Name="+URLEncode("-*{Mahmoud}*-")+ "&Address=Egypt&Phone=123456&Age=28&Notes=Programmer", :title = "Test URL Encode" ]) } Screen Shot: Screen Shot: 53.9. URL Encode 473
Ring Documentation, Release 1.10 53.10 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 New NumbersController { start() } 53.10. Templates 474
Ring Documentation, Release 1.10 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: 53.10. Templates 475
Ring Documentation, Release 1.10 53.11 HTML Special Characters The text() function display HTML special characters. If you want to write html code, use the html() function. 53.11. HTML Special Characters 476
Ring Documentation, Release 1.10 #!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: 53.12 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") ]) newline() text( "Value : " ) newline() newline() divend() formpost("ex16.ring") divstart([ :style = StyleFloatLeft() + StyleWidth("300px") ]) newline() 53.12. Hash Functions 477
Ring Documentation, Release 1.10 textbox([ :name = "Value" ]) newline() newline() submit([ :value = "Send" ]) divend() formend() } Screen Shot: The Response #!ring -cgi Load "weblib.ring" Import System.Web New Page { boxstart() text( "Hash Result" ) newline() boxend() divstart([ :style = styleFloatLeft() + styleWidth("100%") ]) newline() text( "Value : " + aPageVars["Value"] ) newline() text( "MD5 : " + MD5(aPageVars["Value"]) ) newline() text( "SHA1 : " + SHA1(aPageVars["Value"]) ) newline() text( "SHA256 : " + SHA256(aPageVars["Value"]) ) newline() text( "SHA224 : " + SHA224(aPageVars["Value"]) ) newline() text( "SHA384 : " + SHA384(aPageVars["Value"]) ) newline() text( "SHA512 : " + SHA512(aPageVars["Value"]) ) newline() divend() } Screen Shot: 53.12. Hash Functions 478
Ring Documentation, Release 1.10 53.13 Random Image #!ring -cgi Load "weblib.ring" Import System.Web cUploadPath = "C:/Apache2.2/htdocs/ringapp/upload/" New Page { boxstart() text( "Random Test") newline() boxend() divstart([ :style = styleFloatLeft() + styleWidth("400px") ]) newline() aList = dir(cUploadPath) if len(aList) > 0 nIndex = random(len(aList)) if nindex = 0 nIndex = 1 ok cItem = "upload/" + aList[nIndex][1] newline() image( [ :url = cItem , :alt = :image ] ) else text("No images!") newline() ok divend() } Screen Shot: 53.13. Random Image 479
Ring Documentation, Release 1.10 53.14 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 listart([]) 53.14. HTML Lists 480
Ring Documentation, Release 1.10 cFuncName = "btn"+x+"()" button([ :onclick = cFuncName , :value = x]) script(scriptfuncalert(cFuncName,string(x))) liend() next ulend() } Screen Shot: 53.14. HTML Lists 481
Ring Documentation, Release 1.10 53.15 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: 53.15. HTML Tables 482
Ring Documentation, Release 1.10 53.16 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: 53.16. Gradient 483
Ring Documentation, Release 1.10 53.17 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 { TD { WIDTH="10%" text("Name : " ) } 53.17. Generating Pages using Objects 484
Ring Documentation, Release 1.10 TD { Input { type = "text" } } } TR { TD { WIDTH="10%" text("Email : " ) } TD { Input { type = "text" } } } TR { TD { WIDTH="10%" text("Password : " ) } TD { Input { type = "password" } } } TR { TD { WIDTH="10%" text("Notes") } TD { TextArea { width="100%" rows = 10 cols = 10 text("type text here...") } } } TR { TD { WIDTH="10%" text("Gender") } TD { select { width = "100%" option { text("Male") } option { text("Female") } } } } TR { TD { WIDTH="10%" text("Role") } TD { select { multiple = "multiple" width = "100%" option { text("student") } option { text("admin") } } } } } Input { type = "submit" value = "send" } Image { src="upload/profile1.jpg" alt="profile"} Input { type = "checkbox" value = "Old Member"} text("old member") Input { type = "range" min=1 max=100} Input { type = "number" min=1 max=100} Input { type = "radio" color="black" name="one" value = "one"} text("one") } } div { color = "white" 53.17. Generating Pages using Objects 485
Ring Documentation, Release 1.10 backgroundcolor = "blue" width = "100%" UL { LI { TEXT("ONE") } LI { TEXT("TWO") } LI { TEXT("THREE") } } } div { audio { src = "horse.ogg" type = "audio/ogg" } video { width = 320 height = 240 src = "movie.mp4" type = "video/mp4" } Input { type = "color" value = "#ff0000" onchange = "clickColor(0, -1, -1, 5)" } } } Screen Shot: 53.17. Generating Pages using Objects 486
Ring Documentation, Release 1.10 53.17. Generating Pages using Objects 487
Ring Documentation, Release 1.10 53.18 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 53.18. HtmlPage Class 488
Ring Documentation, Release 1.10 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()) 53.19 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" ]) divstart([ :class = "jumbotron" ]) h1("Bootstrap Page") divend() 53.19. Using Bootstrap Library using Functions 489
Ring Documentation, Release 1.10 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: 53.20 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 53.20. Using Bootstrap Library using Objects 490
Ring Documentation, Release 1.10 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-sucess btn-sm" text("sucess") } 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") } } div { classname = "col-sm-4" Button { classname = "btn btn-default btn-block" text("default") } Button { classname = "btn btn-primary btn-block" text("primary") } Button { classname = "btn btn-sucess btn-block" text("sucess") } Button { classname = "btn btn-info btn-block" text("info") } Button { classname = "btn btn-warning btn-block" text("warning") } Button { classname = "btn btn-danger btn-block" text("danger") } Button { classname = "btn btn-link btn-block" text("link") } } 53.20. Using Bootstrap Library using Objects 491
Ring Documentation, Release 1.10 div { classname = "col-sm-4" div { classname = "btn-group" button { classname="btn btn-primary" text("one") } button { classname="btn btn-primary" text("two") } button { classname="btn btn-primary" text("three") } } } div { classname = "col-sm-4" div { classname = "btn-group btn-group-lg" button { classname="btn btn-primary" text("one") } button { classname="btn btn-primary" text("two") } button { classname="btn btn-primary" text("three") } } } div { classname = "col-sm-4" div { classname = "btn-group-vertical btn-group-lg" button { classname="btn btn-primary" text("one") } button { classname="btn btn-primary" text("two") } button { classname="btn btn-primary" text("three") } } } } div { classname="modal fade" id="myModal" role="dialog" div { classname = "modal-dialog modal-lg" div { classname="modal-content" div { classname="modal-header" button { classname="close" datadismiss="modal" html("&times") } h4 { classname="modal-title" text("Modal Header") } } div { classname = "modal-body" p { text("This is a large model.") } } div { classname="modal-footer" button { classname = "btn btn-default" datadismiss="modal" text("close") } } } } } } } Screen Shot: 53.20. Using Bootstrap Library using Objects 492
Ring Documentation, Release 1.10 53.21 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. #!ring -cgi Load "weblib.ring" Load "datalib.ring" Import System.Web website = "ex24.ring" New SalaryController { Routing() } 53.21. CRUD Example using MVC 493
Ring Documentation, Release 1.10 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: 53.21. CRUD Example using MVC 494
Ring Documentation, Release 1.10 53.22 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 53.22. Users registration and Login 495
Ring Documentation, Release 1.10 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" Load "datalib.ring" Load "ex25_users.ring" Import System.Web website = "ex25.ring" New UsersController { Routing() } Screen Shot: 53.22. Users registration and Login 496
Ring Documentation, Release 1.10 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") cellend() cellstart([ :style = stylewidth("80%") ]) textbox([:name = "username", :style = stylewidth("100%")]) cellend() rowend() rowstart([]) cellstart([ :Style = styleheight(30)]) text("Password") cellend() cellstart([]) textbox([:name = "password" , :type = "password"]) 53.22. Users registration and Login 497
Ring Documentation, Release 1.10 cellend() rowend() rowstart([]) cellstart([ :style = styleheight(30)]) text("Email") cellend() cellstart([]) textbox([:name = "email" , :style = stylewidth("100%")]) cellend() rowend() rowstart([]) cellstart([ :style = styleheight(30)]) cellend() cellstart([ :style = styleheight(30)]) submit([:value = "Register" ]) cellend() rowend() tableend() formend() divend() divend() } Screen Shot: The Registration response #!ring -cgi Load "weblib.ring" Load "datalib.ring" Load "ex25_users.ring" 53.22. Users registration and Login 498
Ring Documentation, Release 1.10 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"]) text("New User Created!") newline() text("User Name : " + aPageVars["username"]) newline() } oUser.Disconnect() See the next code for the Login page #!ring -cgi Load "weblib.ring" Load "datalib.ring" Import System.Web website = "ex28.ring" new page { boxstart() text( "Login") newline() boxend() divstart([:style = stylegradient(6) + stylesize("100%","95%") ]) link([ :url = website, :title = "back" , :style = stylecolor("white")]) newline() divstart([ :style= styledivcenter("500","130") + stylegradient(52) ]) formpost("ex29.ring") tablestart([ :Style = stylemarginleft("2%") + stylemargintop("2%") + stylewidth("90%") ]) rowstart([]) cellstart([:style = stylewidth("20%") + styleheight(30)]) text("User Name") cellend() cellstart([ :style = stylewidth("80%") ]) textbox([:name = "username", :style = stylewidth("100%")]) cellend() 53.22. Users registration and Login 499
Ring Documentation, Release 1.10 rowend() rowstart([]) cellstart([ :style = styleheight(30)]) text("Password") cellend() cellstart([]) textbox([:name = "password" , :type = "password"]) cellend() rowend() rowstart([]) cellstart([ :style = styleheight(30) ]) cellend() cellstart([]) submit([:value = "Login" ]) cellend() rowend() tableend() formend() divend() divend() } Screen Shot: The response page #!ring -cgi Load "weblib.ring" Load "datalib.ring" Load "ex25_users.ring" Import System.Web 53.22. Users registration and Login 500
Ring Documentation, Release 1.10 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 #!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() 53.23 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 53.23. Database, ModelBase & ControllerBase classes 501
Ring Documentation, Release 1.10 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) 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]) + "'," 53.23. Database, ModelBase & ControllerBase classes 502
Ring Documentation, Release 1.10 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) 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 53.23. Database, ModelBase & ControllerBase classes 503
Ring Documentation, Release 1.10 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 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 53.23. Database, ModelBase & ControllerBase classes 504
Ring Documentation, Release 1.10 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" 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 53.23. Database, ModelBase & ControllerBase classes 505
Ring Documentation, Release 1.10 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 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() 53.24 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 53.24. WebLib API 506
Ring Documentation, Release 1.10 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. 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. 53.24. WebLib API 507
Ring Documentation, Release 1.10 53.25 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. 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. 53.26 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> Continued on next page 53.25. Application Class 508
Ring Documentation, Release 1.10 Table 53.2 – continued from previous page Method Parameters Description 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> 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 53.26. Page Class 509
Ring Documentation, Release 1.10 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 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 53.27 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 53.27. ScriptFunctions Class 510
Ring Documentation, Release 1.10 53.28 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. 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;” 53.29 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. 53.28. StyleFunctions Class 511
Ring Documentation, Release 1.10 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. 53.30 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 53.30. HtmlPage Class 512
CHAPTER FIFTYFOUR DEPLOYING WEB APPLICATIONS IN THE CLOUD In this chapter we will learn about deploying Ring Web Applications in the Cloud using Heroku 54.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/ 54.2 Usage To use this project and deploy it on Heroku 513
Ring Documentation, Release 1.10 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 projet 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 54.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" If you are using TortoiseGit, From windows explorer, select the file Right click —> Properties —> Git —> Executable (+x) Then commit and deploy! 54.3. Ring source code files and permissions 514
Ring Documentation, Release 1.10 54.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!") } 54.5 Application Database When you depoly 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 54.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 54.4. Hello World program 515
Ring Documentation, Release 1.10 54.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) 54.7. Local Tests 516
CHAPTER FIFTYFIVE USING RINGLIBCURL In this chapter we will learn about using RingLibCurl 55.1 Get Request Example: load "libcurl.ring" curl = curl_easy_init() curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1) curl_easy_setopt(curl, CURLOPT_URL, "http://ring-lang.sf.net") curl_easy_perform(curl) curl_easy_cleanup(curl) 55.2 Post Request Example: load "libcurl.ring" curl = curl_easy_init() cPostThis = "page=4&Number1=4&Number2=5" curl_easy_setopt(curl, CURLOPT_URL, "http://localhost/ringapp/index.ring?page=3") curl_easy_setopt(curl, CURLOPT_POSTFIELDS, cPostThis) curl_easy_perform(curl) curl_easy_cleanup(curl) 55.3 Facebook Login Example: 517
Ring Documentation, Release 1.10 load "libcurl.ring" see "Enter Email : " give $login_email See "Enter Password : " give $login_pass curl = curl_easy_init() curl_easy_setopt(curl, CURLOPT_URL, 'https://www.facebook.com/login.php') curl_easy_setopt(curl, CURLOPT_POSTFIELDS,'charset_test=j u s t a t e s t'+ ' &email='+urlencode($login_email)+'&pass='+ urlencode($login_pass)+'&login=Login') curl_easy_setopt(curl, CURLOPT_POST, 1) curl_easy_setopt(curl, CURLOPT_HEADER, 0) curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1) curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "cookies.txt") curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "cookies.txt") curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U;"+ " Windows NT 5.1; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3") curl_easy_setopt(curl, CURLOPT_REFERER, "http://www.facebook.com") curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE) curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2) mylist = curl_slist_append(NULL,'Accept-Charset: utf-8') curl_slist_append(mylist,'Accept-Language: en-us,en;q=0.7,bn-bd;q=0.3') curl_slist_append(mylist,'Accept: text/xml,application/xml,'+ 'application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5') curl_easy_setopt(curl, CURLOPT_HTTPHEADER, mylist) curl_easy_setopt(curl, CURLOPT_COOKIESESSION, false) curl_easy_perform(curl) curl_easy_cleanup(curl) Func URLEncode cStr cOut = "" for x in cStr if isalnum(x) cOut += x but x = " " cOut += "+" else cOut += "%"+str2hex(x) ok next return cOut 55.4 Save Output to String Example: load "libcurl.ring" curl = curl_easy_init() curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1) 55.4. Save Output to String 518
Ring Documentation, Release 1.10 curl_easy_setopt(curl, CURLOPT_URL, "http://ring-lang.sf.net") cOutput = curl_easy_perform_silent(curl) See "Output:" + nl see cOutput curl_easy_cleanup(curl) 55.5 Get Stock Data From Yahoo Example: Load "libcurl.ring" ### Part 1 --- Get Crumb and Cookie ----------------------------------------- See "Start curl_easy_init(): "+ nl curl = curl_easy_init() ### >>> HANDLE >>> 01006BD0 CURL 0 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1) curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "cookies.txt") curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "cookies.txt") curl_easy_setopt(curl, CURLOPT_URL, "https://finance.yahoo.com/quote/AMZN/history") ### HTML Data >>> STDOUT Window, Use curl_easy_perform_silent >>> String cOutput = curl_easy_perform_silent(curl) ### GO Get Data >>> String ### Extract Crumb from data ### "CrumbStore":{"crumb":"abcdefghijk"}, if cOutput != NULL newStr1 = substr(cOutput, substr(cOutput, '"CrumbStore":{"crumb":"' ), 48 ) nPosS = substr(newStr1, ':"' ) ; ### Start of crumb -2 nPosE = substr(newStr1, '"}' ) ; ### End of crumb nCount = nPosE - nPosS -2 ### size of crumb myCrumb = substr(newStr1, nPosS +2, nCount) See "myCrumb.: |"+ myCrumb +"|" +nl ### UniCode "u002F" replace it with "/" if substr( myCrumb, "u002F") myCrumb = substr( myCrumb, "u002F", "/") See "myCrumb2: |"+ myCrumb +"|"+ nl ok else See "No Connectivity to Yahoo. Looking for Cookie and Crumb." +nl +nl ok ### Part 2 --- Send URL with Crumb, and Cookie ----------------------------------------- 55.5. Get Stock Data From Yahoo 519
Ring Documentation, Release 1.10 ### Send URL+Crumb to Yahoo to fetch 1st stock history data, $url = "https://query1.finance.yahoo.com/v7/finance/download/AMZN"+ "?period1=1277856000&period2=1498777545&interval=1wk" + "&events=history&crumb=" + myCrumb curl_easy_setopt(curl, CURLOPT_URL, $url); cStr = curl_easy_perform_silent(curl) See cStr curl_easy_cleanup(curl) ### REMEMBER to CLOSE CURL Output: myCrumb.: |sEEeW97mxvN| Date,Open,High,Low,Close,Adj Close,Volume 2010-07-05,110.650002,117.480003,109.000000,117.260002,117.260002,21000400 2010-07-12,117.809998,124.879997,117.320000,118.489998,118.489998,29407300 2010-07-19,118.379997,121.250000,105.800003,118.870003,118.870003,74252100 55.5. Get Stock Data From Yahoo 520
CHAPTER FIFTYSIX USING RINGZIP In this chapter we will learn about using RingZip 56.1 Create Zip File Example : Create myfile.zip contains 4 files load "ziplib.ring" oZip = zip_openfile("myfile.zip",'w') zip_addfile(oZip,"test.c") zip_addfile(oZip,"zip.c") zip_addfile(oZip,"zip.h") zip_addfile(oZip,"miniz.h") zip_close(oZip) 56.2 Extract Zip File Example : Extract myfile.zip to myfolder folder. load "ziplib.ring" zip_extract_allfiles("myfile.zip","myfolder") 56.3 Print Files in Zip file Example : Print file names in the myfile.zip load "ziplib.ring" oZip = zip_openfile("myfile.zip",'r') for x=1 to zip_filescount(oZip) see zip_getfilenamebyindex(oZip,x) + nl next zip_close(oZip) 56.4 Using RingZip Classes The RingZip library comes with two classes. The Zip class and the ZipEntry class. 521
Ring Documentation, Release 1.10 Example (1): load "ziplib.ring" new Zip { setFileName("myfile.zip") open("w") newEntry() { open("test.c") writefile("test.c") close() } close() } Example (2): load "ziplib.ring" new Zip { SetFileName("myfile.zip") Open("w") AddFile("test.c") AddFile("zip.c") AddFile("zip.h") AddFile("miniz.h") Close() } Example (3): load "ziplib.ring" new zip { SetFileName("myfile.zip") ExtractAllFiles("myfolder") } Example (4): load "ziplib.ring" new Zip { SetFileName("myfile.zip") Open("r") see FilesCount() Close() } Example (5): load "ziplib.ring" new Zip { SetFileName("myfile.zip") Open("r") for x = 1 to filescount() See GetFileNameByIndex(x) + nl next Close() 56.4. Using RingZip Classes 522
Ring Documentation, Release 1.10 } 56.5 Zip Class Reference Methods: Method Description/Output SetFileName(cName) Set the Zip file name GetFileName() Return the Zip file name Open(cMode) Open File, cMode = “a”, “w” or “r” Close() Close the Zip File AddFile(cFileName) Add file to the Zip file ExtractAllFiles(cFolder) Extract all files from the Zip file FilesCount() Return files count in the Zip file GetFileNameByIndex(nIndex) Return file name in the Zip file by file index NewEntry() Create new ZipEntry object 56.6 ZipEntry Class Reference Methods: Method Description/Output Open(cFileName) Open new Entry WriteFile(cFileName) Write File to the Entry WriteString(cString) Write String to the Entry Close() Close the Entry 56.5. Zip Class Reference 523
CHAPTER FIFTYSEVEN GRAPHICS AND 2D GAMES 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. 57.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) al_clear_to_color(al_map_rgb(255,0,255)) 524
Ring Documentation, Release 1.10 for x = 1 to 30 bouncer_x += x bouncer_y += x al_set_target_bitmap(al_get_backbuffer(display)) al_clear_to_color(al_map_rgb(0,0,0)) al_draw_bitmap(bouncer, bouncer_x, bouncer_y, 0) al_draw_bitmap(bouncer, 200+bouncer_x,200+ bouncer_y, 0) al_flip_display() al_rest(0.1) next al_clear_to_color(al_map_rgb(255,255,255)) image = al_load_bitmap("man2.jpg") al_draw_bitmap(image,200,200,0) al_flip_display() al_rest(2) 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) FPS = 60 timer = al_create_timer(1.0 / FPS) al_register_event_source(event_queue, al_get_timer_event_source(timer)) al_start_timer(timer) redraw = true SCREEN_W = 640 SCREEN_H = 480 BOUNCER_SIZE = 32 bouncer_x = SCREEN_W / 2.0 - BOUNCER_SIZE / 2.0 bouncer_y = SCREEN_H / 2.0 - BOUNCER_SIZE / 2.0 bouncer_dx = -4.0 bouncer_dy = 4.0 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()) KEY_UP = 1 KEY_DOWN = 2 KEY_LEFT = 3 KEY_RIGHT = 4 Key = [false,false,false,false] 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 57.1. Drawing, Animation and Input 525
Ring Documentation, Release 1.10 # 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 key[KEY_LEFT] = false on ALLEGRO_KEY_RIGHT key[KEY_RIGHT] = false on ALLEGRO_KEY_ESCAPE 57.1. Drawing, Animation and Input 526
Ring Documentation, Release 1.10 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 57.1. Drawing, Animation and Input 527
Ring Documentation, Release 1.10 Then we see two rectangles are moving on the screen 57.1. Drawing, Animation and Input 528
Ring Documentation, Release 1.10 Then we see an image displayed on the screen 57.1. Drawing, Animation and Input 529
Ring Documentation, Release 1.10 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 Keyborad 57.1. Drawing, Animation and Input 530
Ring Documentation, Release 1.10 57.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: 57.2. Using TrueType Fonts 531
Ring Documentation, Release 1.10 57.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) al_destroy_allegro_sample_id(sampleid) 57.3. Playing Sound Files 532
Ring Documentation, Release 1.10 al_destroy_sample(sample) al_destroy_display(display) al_exit() 57.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: 57.4. Scaling and Rotating Images 533
Ring Documentation, Release 1.10 57.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) 57.5. Display Transparent Image 534
Ring Documentation, Release 1.10 Screen Shot: 57.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 cAppName = "Threads Application" 57.6. Using Threads 535
Ring Documentation, Release 1.10 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 Thread(2) : Application Name : Threads Application *****1 *****2 57.6. Using Threads 536
Ring Documentation, Release 1.10 *****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 57.6. Using Threads 537
CHAPTER FIFTYEIGHT USING RINGLIBSDL In this chapter we will learn about using RingLibSDL to create games based on the LibSDL, SDLImage, SDLTTF and SDLMixer libraries. Tip: RingLibSDL is not distributed with the binary releases for desktop which uses RingAllegro Note: To use RingLibSDL, Check ring/android/ringlibsdl folder. 58.1 Create Window Example: Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN) SDL_Delay(2000) SDL_DestroyWindow(win) SDL_Quit() 58.2 Display Image Example: Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN) ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC ) bmp = SDL_LoadBMP("hello.bmp") tex = SDL_CreateTextureFromSurface(ren,bmp) SDL_FreeSurface(bmp) SDL_RenderClear(ren) SDL_RenderCopy2(ren,tex) SDL_RenderPresent(ren) SDL_Delay(2000) SDL_DestroyTexture(tex) SDL_DestroyRenderer(ren) SDL_DestroyWindow(win) SDL_Quit() 538
Ring Documentation, Release 1.10 58.3 Switch between two images Example: Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN) ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC ) bmp = SDL_LoadBMP("hello.bmp") tex = SDL_CreateTextureFromSurface(ren,bmp) SDL_FreeSurface(bmp) bmp = SDL_LoadBMP("hello2.bmp") tex2 = SDL_CreateTextureFromSurface(ren,bmp) SDL_FreeSurface(bmp) for x = 1 to 10 showtex(tex) showtex(tex2) next SDL_DestroyTexture(tex) SDL_DestroyTexture(tex2) SDL_DestroyRenderer(ren) SDL_DestroyWindow(win) SDL_Quit() func showtex oTex SDL_RenderClear(ren) SDL_RenderCopy2(ren,oTex) SDL_RenderPresent(ren) SDL_Delay(200) 58.4 Draw Rectangle Example: Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN) ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC ) SDL_RenderClear(ren) 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) SDL_RenderPresent(ren) SDL_Delay(2000) SDL_DestroyRenderer(ren) SDL_DestroyWindow(win) SDL_Quit() 58.3. Switch between two images 539
Ring Documentation, Release 1.10 58.5 Display PNG Images Example: Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN) ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC ) bmp = IMG_Load("hello3.png") tex = SDL_CreateTextureFromSurface(ren,bmp) SDL_FreeSurface(bmp) SDL_RenderClear(ren) SDL_RenderCopy2(ren,tex) SDL_RenderPresent(ren) SDL_Delay(2000) SDL_DestroyTexture(tex) SDL_DestroyRenderer(ren) SDL_DestroyWindow(win) SDL_Quit() 58.6 Use TTF Fonts Example: Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN) ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC ) SDL_RenderClear(ren) TTF_Init() font = TTF_OpenFont("pirulen.ttf", 16) color = sdl_new_sdl_color() sdl_set_sdl_color_r(color,0) sdl_set_sdl_color_g(color,255) sdl_set_sdl_color_b(color,0) text = TTF_RenderText_Solid(font,"Welcome to the Ring language",color) surface = SDL_GetWindowSurface(win) SDL_BlitSurface(text, nullpointer(), surface, nullpointer()) SDL_UpdateWindowSurface(win) SDL_Delay(2000) SDL_Destroy_SDL_Color(color) SDL_FreeSurface(text) TTF_CloseFont(font) SDL_DestroyRenderer(ren) SDL_DestroyWindow(win) SDL_Quit() 58.7 Display Transparent Images Example: 58.5. Display PNG Images 540
Ring Documentation, Release 1.10 Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) flags = IMG_INIT_JPG | IMG_INIT_PNG IMG_Init(flags) win = SDL_CreateWindow("Hello World!", 100, 100, 800, 600, SDL_WINDOW_SHOWN) ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC ) bmp = IMG_Load("stars.jpg") tex = SDL_CreateTextureFromSurface(ren,bmp) SDL_FreeSurface(bmp) SDL_RenderClear(ren) SDL_RenderCopy(ren,tex,nullpointer(),nullpointer()) SDL_DestroyTexture(tex) bmp = IMG_Load("player.png") # Image - Set Transparent color (white) myformat = sdl_get_sdl_surface_format(bmp) white = SDL_MapRGB(myformat, 255, 255, 255) SDL_SetColorKey(bmp, SDL_True, white) tex = SDL_CreateTextureFromSurface(ren,bmp) SDL_FreeSurface(bmp) rect = sdl_new_sdl_rect() sdl_set_sdl_rect_x(rect,0) sdl_set_sdl_rect_y(rect,0) sdl_set_sdl_rect_w(rect,100) sdl_set_sdl_rect_h(rect,100) SDL_RenderCopy(ren,tex,nullpointer(),rect) SDL_SetTextureBlendMode(tex,2) SDL_SetTextureAlphaMod(tex,255) sdl_set_sdl_rect_x(rect,200) sdl_set_sdl_rect_y(rect,200) sdl_set_sdl_rect_w(rect,100) sdl_set_sdl_rect_h(rect,100) SDL_RenderCopy(ren,tex,nullpointer(),rect) SDL_DestroyTexture(tex) SDL_Destroy_SDL_Rect(rect) SDL_RenderPresent(ren) SDL_Delay(2000) SDL_DestroyRenderer(ren) SDL_DestroyWindow(win) SDL_Quit() 58.8 Close Window Event Example: Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) 58.8. Close Window Event 541
Ring Documentation, Release 1.10 win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN) myevent = sdl_new_sdl_event() while true thevent = sdl_pollevent(myevent) switch sdl_get_sdl_event_type(myevent) on sdl_get_sdl_quit() exit on sdl_get_sdl_keydown() Key = SDL_GET_SDL_Event_key_keysym_sym(myevent) if key = 27 exit ok off end SDL_DestroyWindow(win) SDL_Quit() 58.9 Mouse Events Example: Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) win = SDL_CreateWindow("Mouse Events ", 100, 100, 640, 480, SDL_WINDOW_SHOWN) TTF_Init() font = TTF_OpenFont("pirulen.ttf", 16) color = sdl_new_sdl_color() sdl_set_sdl_color_r(color,0) sdl_set_sdl_color_g(color,255) sdl_set_sdl_color_b(color,0) surface = SDL_GetWindowSurface(win) myevent = sdl_new_sdl_event() while true cMsg = "" sdl_pollevent(myevent) switch sdl_get_sdl_event_type(myevent) on SDL_QUIT exit on SDL_KEYDOWN Key = SDL_GET_SDL_Event_key_keysym_sym(myevent) if key = 27 exit ok on SDL_MOUSEBUTTONDOWN if sdl_get_Sdl_Event_button_button(myevent) = SDL_BUTTON_LEFT SDL_SETWINDOWTITLE(win, " Button_Left_Down " ) but sdl_get_Sdl_Event_button_button(myevent) = SDL_BUTTON_MIDDLE SDL_SETWINDOWTITLE(win, " Button_Middle_Down " ) but sdl_get_Sdl_Event_button_button(myevent) = SDL_BUTTON_RIGHT SDL_SETWINDOWTITLE(win, " Button_Right_Down " ) ok on SDL_MOUSEMOTION 58.9. Mouse Events 542
Ring Documentation, Release 1.10 sdl_fillrect(surface,nullpointer(),0) if sdl_get_sdl_event_motion_xrel(myevent) < 0 cMsg += " Left " else cMsg += " Right " ok if sdl_get_sdl_event_motion_yrel(myevent) < 0 cMsg += " Up " else cMsg += " Down " ok cMsg += " x = " + sdl_get_sdl_event_motion_x(myevent) cMsg += " y = " + sdl_get_sdl_event_motion_y(myevent) showmsg(cMsg) off end SDL_Destroy_SDL_Color(Color) TTF_CloseFont(font) SDL_DestroyWindow(win) SDL_Quit() func showmsg mymsg text = TTF_RenderText_Solid(font,mymsg,color) SDL_BlitSurface(text, nullpointer(), surface, nullpointer()) SDL_UpdateWindowSurface(win) SDL_FreeSurface(text) 58.10 Play Sound Example: Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN) Mix_OpenAudio( 44100, MIX_DEFAULT_FORMAT , 2, 10000) Mix_AllocateChannels(4) sound = Mix_LoadWav( "sound.wav" ) Mix_VolumeChunk(sound,1) Mix_PlayChannel(1,sound,0) myevent = sdl_new_sdl_event() while true thevent = sdl_pollevent(myevent) switch sdl_get_sdl_event_type(myevent) on sdl_get_sdl_quit() exit on sdl_get_sdl_keydown() Key = SDL_GET_SDL_Event_key_keysym_sym(myevent) if key = 27 exit ok off end Mix_FreeChunk( sound ) Mix_CloseAudio() 58.10. Play Sound 543
Ring Documentation, Release 1.10 Mix_Quit() SDL_DestroyWindow(win) SDL_Quit() 58.10. Play Sound 544
CHAPTER FIFTYNINE USING RINGLIBUV In this chapter we will learn about using RingLibuv Note: To use RingLibuv, Check ring/extensions/ringlibuv folder. Information from the library website: http://libuv.org/ Libuv is a multi-platform support library with a focus on asynchronous I/O. Feature highlights • Full-featured event loop backed by epoll, kqueue, IOCP, event ports. • Asynchronous TCP and UDP sockets • Asynchronous DNS resolution • Asynchronous file and file system operations • File system events • ANSI escape code controlled TTY • IPC with socket sharing, using Unix domain sockets or named pipes (Windows) • Child processes • Thread pool • Signal handling • High resolution clock • Threading and synchronization primitives 59.1 First Application using RingLibuv Example: load "libuv.ring" func main myloop = new_uv_loop_t() uv_loop_init(myloop) ? "Now quitting" uv_run(myloop, UV_RUN_DEFAULT) 545
Ring Documentation, Release 1.10 uv_loop_close(myloop) destroy_uv_loop_t(myloop) Output: Now quitting 59.2 The Events Loop Example: load "libuv.ring" counter = 0 idler = NULL func main idler = new_uv_idle_t() uv_idle_init(uv_default_loop(), idler) uv_idle_start(idler, "wait()") ? "Idling..." uv_run(uv_default_loop(), UV_RUN_DEFAULT); uv_loop_close(uv_default_loop()); destroy_uv_idle_t(idler) func wait counter++ if counter >= 100000 uv_idle_stop(idler) ok Output: Idling... 59.3 Server Example Example: load "libuv.ring" ? "Testing RingLibuv - Server Side" DEFAULT_PORT = 13370 DEFAULT_BACKLOG = 1024 addr = new_sockaddr_in() server = NULL client = NULL myloop = NULL func main myloop = uv_default_loop() server = new_uv_tcp_t() 59.2. The Events Loop 546
Ring Documentation, Release 1.10 uv_tcp_init(myloop, server) uv_ip4_addr("127.0.0.1", DEFAULT_PORT, addr) uv_tcp_bind(server, addr, 0) r = uv_listen(server, DEFAULT_BACKLOG, "newconnection()") if r ? "Listen error " + uv_strerror(r) return 1 ok uv_run(myloop, UV_RUN_DEFAULT) destroy_uv_tcp_t(server) destroy_uv_sockaddr_in(addr) func newconnection ? "New Connection" aPara = uv_Eventpara(server,:connect) nStatus = aPara[2] if nStatus < 0 ? "New connection error : " + nStatus return ok client = new_uv_tcp_t() uv_tcp_init(myloop, client) if uv_accept(server, client) = 0 uv_read_start(client, uv_myalloccallback(), "echo_read()") ok func echo_read aPara = uv_Eventpara(client,:read) nRead = aPara[2] buf = aPara[3] if nRead > 0 req = new_uv_write_t() wrbuf = uv_buf_init(get_uv_buf_t_base(buf), nread) uv_write(req, client, wrbuf, 1, "echo_write()") ? uv_buf2str(wrbuf) message = "message from the server to the client" buf = new_uv_buf_t() set_uv_buf_t_len(buf,len(message)) set_uv_buf_t_base(buf,varptr("message","char *")) uv_write(req, client, buf, 1, "echo_write()") ok func echo_write aPara = uv_Eventpara(client,:read) req = aPara[1] Output: When we run the client, We will see the message “New Connection” Then the message “hello from the client” Testing RingLibuv - Server Side New Connection hello from the client 59.3. Server Example 547
Ring Documentation, Release 1.10 59.4 Client Example Example: load "libuv.ring" ? "Testing RingLibuv - Client Side" DEFAULT_PORT = 13370 DEFAULT_BACKLOG = 1024 addr = new_sockaddr_in() connect = NULL buffer = null socket = null func main myloop = uv_default_loop() Socket = new_uv_tcp_t() connect = new_uv_connect_t() uv_tcp_init(myloop, Socket) uv_ip4_addr("127.0.0.1", DEFAULT_PORT, addr) uv_tcp_connect(connect,Socket, addr, "connect()") uv_run(myloop, UV_RUN_DEFAULT) destroy_uv_tcp_t(socket) destroy_uv_connect_t(connect) func connect ? "Client: Start Connection" aPara = uv_Eventpara(connect,:connect) req = aPara[1] nStatus = aPara[2] if nStatus = -1 ? "Error : on_write_end " return ok buf = new_uv_buf_t() message = "hello from the client" set_uv_buf_t_len(buf,len(message)) set_uv_buf_t_base(buf,varptr("message","char *")) tcp = get_uv_connect_t_handle(req) write_req = new_uv_write_t() buf_count = 1 uv_write(write_req, tcp, buf, buf_count, "on_write_end()") func on_write_end uv_read_start(socket, uv_myalloccallback(), "echo_read()") func echo_read aPara = uv_Eventpara(socket,:read) nRead = aPara[2] buf = aPara[3] if nRead > 0 wrbuf = uv_buf_init(get_uv_buf_t_base(buf), nread); ? uv_buf2str(wrbuf) ok Output: 59.4. Client Example 548
Ring Documentation, Release 1.10 We will run the client after the server Testing RingLibuv - Client Side Client: Start Connection hello from the client message from the server to the client 59.5 Server Example Using Classes Example: load "libuv.ring" load "objectslib.ring" ? "Testing RingLibuv - Server Side - Using Classes" open_object(:MyServer) class MyServer from ObjectControllerParent DEFAULT_PORT = 13370 DEFAULT_BACKLOG = 1024 addr = new_sockaddr_in() server = NULL client = NULL myloop = NULL func start myloop = uv_default_loop() server = new_uv_tcp_t() uv_tcp_init(myloop, server) uv_ip4_addr("127.0.0.1", DEFAULT_PORT, addr) uv_tcp_bind(server, addr, 0) r = uv_listen(server, DEFAULT_BACKLOG, Method(:newconnection) ) if r ? "Listen error " + uv_strerror(r) return 1 ok uv_run(myloop, UV_RUN_DEFAULT) destroy_uv_tcp_t(server) destroy_uv_sockaddr_in(addr) func newconnection ? "New Connection" aPara = uv_Eventpara(server,:connect) nStatus = aPara[2] if nStatus < 0 ? "New connection error : " + nStatus return ok client = new_uv_tcp_t() uv_tcp_init(myloop, client) if uv_accept(server, client) = 0 uv_read_start(client, uv_myalloccallback(), Method(:echo_read)) ok 59.5. Server Example Using Classes 549
Ring Documentation, Release 1.10 func echo_read aPara = uv_Eventpara(client,:read) nRead = aPara[2] buf = aPara[3] if nRead > 0 req = new_uv_write_t() wrbuf = uv_buf_init(get_uv_buf_t_base(buf), nread) uv_write(req, client, wrbuf, 1, Method(:echo_write)) ? uv_buf2str(wrbuf) message = "message from the server to the client" buf = new_uv_buf_t() set_uv_buf_t_len(buf,len(message)) set_uv_buf_t_base(buf,varptr("message","char *")) uv_write(req, client, buf, 1, Method(:echo_write)) ok func echo_write aPara = uv_Eventpara(client,:read) req = aPara[1] Output: When we run the client, We will see the message “New Connection” Then the message “hello from the client” Testing RingLibuv - Server Side - Using Classes New Connection hello from the client 59.6 Client Example Using Classes Example: load "libuv.ring" load "objectslib.ring" ? "Testing RingLibuv - Client Side - Using Classes" open_object(:MyClient) Class MyClient from ObjectControllerParent DEFAULT_PORT = 13370 DEFAULT_BACKLOG = 1024 addr = new_sockaddr_in() connect = NULL buffer = null socket = null func start myloop = uv_default_loop() Socket = new_uv_tcp_t() connect = new_uv_connect_t() uv_tcp_init(myloop, Socket) uv_ip4_addr("127.0.0.1", DEFAULT_PORT, addr) 59.6. Client Example Using Classes 550
Ring Documentation, Release 1.10 uv_tcp_connect(connect,Socket, addr, Method(:connect)) uv_run(myloop, UV_RUN_DEFAULT) destroy_uv_tcp_t(socket) destroy_uv_connect_t(connect) func connect ? "Client: Start Connection" aPara = uv_Eventpara(connect,:connect) req = aPara[1] nStatus = aPara[2] if nStatus = -1 ? "Error : on_write_end " return ok buf = new_uv_buf_t() message = "hello from the client" set_uv_buf_t_len(buf,len(message)) set_uv_buf_t_base(buf,varptr("message","char *")) tcp = get_uv_connect_t_handle(req) write_req = new_uv_write_t() buf_count = 1 uv_write(write_req, tcp, buf, buf_count, Method(:on_write_end)) func on_write_end uv_read_start(socket, uv_myalloccallback(), Method(:echo_read)) func echo_read aPara = uv_Eventpara(socket,:read) nRead = aPara[2] buf = aPara[3] if nRead > 0 wrbuf = uv_buf_init(get_uv_buf_t_base(buf), nread); ? uv_buf2str(wrbuf) ok Output: We will run the client after the server Testing RingLibuv - Client Side - Using Classes Client: Start Connection hello from the client message from the server to the client 59.7 Threads Example Example: load "libuv.ring" ? "Testing RingLibuv - Threads" func main one_id = new_uv_thread_t() two_id = new_uv_thread_t() uv_thread_create(one_id, "one()") uv_thread_create(two_id, "two()") 59.7. Threads Example 551
Ring Documentation, Release 1.10 uv_thread_join(one_id) uv_thread_join(two_id) destroy_uv_thread_t(one_id) destroy_uv_thread_t(two_id) func one ? "Message from the First Thread!" func two ? "Message from the Second Thread!" Output: Testing RingLibuv - Threads Message from the First Thread! Message from the Second Thread! 59.8 Threads Example - Using Classes Example: load "libuv.ring" load "objectslib.ring" ? "Testing RingLibuv - Threads - Using Classes" open_object(:MyThreads) class MyThreads from ObjectControllerParent func Start one_id = new_uv_thread_t() two_id = new_uv_thread_t() uv_thread_create(one_id, Method(:One)) uv_thread_create(two_id, Method(:Two)) uv_thread_join(one_id) uv_thread_join(two_id) destroy_uv_thread_t(one_id) destroy_uv_thread_t(two_id) func one ? "Message from the First Thread!" func Two ? "Message from the Second Thread!" Output: Testing RingLibuv - Threads - Using Classes Message from the First Thread! Message from the Second Thread! 59.8. Threads Example - Using Classes 552
CHAPTER SIXTY 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. 60.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) 60.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 553
Ring Documentation, Release 1.10 60.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/ringlibs/gameengine/gl_allegro.ring • gl_libsdl.ring source code : https://github.com/ring-lang/ring/blob/master/ringlibs/gameengine/gl_libsdl.ring 60.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/ringlibs/gameengine/gameengine.ring 60.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 60.3. Interface to graphics library 554
Ring Documentation, Release 1.10 • 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 60.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. 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. The next table present a group of keywords defined by the class. 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 ot the game objects. 60.7 GameObject Class The next table present the class attributes. 60.6. Game Class 555
Ring Documentation, Release 1.10 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 index of the object in objects list. 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. 60.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. The next table present the class methods. Method Description Draw(oGame) Draw the object 60.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. 60.8. Sprite Class 556
Ring Documentation, Release 1.10 Method Description Draw(oGame) Draw the object 60.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 60.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 60.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 60.10. Animate Class 557
Ring Documentation, Release 1.10 60.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. Screen Shot: 60.14 Using the Game Engine - Drawing Text Load "gameengine.ring" # Give Control to the Game Engine func main # Called by the Game Engine 60.13. Using the Game Engine - Creating the Game Window 558
Ring Documentation, Release 1.10 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: 60.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 60.15. Using the Game Engine - Moving Text 559
Ring Documentation, Release 1.10 { 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 } } # Start the Events Loop Screen Shot: 60.15. Using the Game Engine - Moving Text 560
Ring Documentation, Release 1.10 60.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 60.16. Using the Game Engine - Playing Sound 561
Ring Documentation, Release 1.10 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 60.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 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 60.17. Using the Game Engine - Animation 562
Ring Documentation, Release 1.10 60.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 60.18. Using the Game Engine - Animation and Functions 563
Ring Documentation, Release 1.10 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 } } } } 60.18. Using the Game Engine - Animation and Functions 564
Ring Documentation, Release 1.10 60.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 60.19. Using the Game Engine - Sprite - Automatic Movement using Keyboard 565
Ring Documentation, Release 1.10 60.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 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 60.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 { 60.20. Using the Game Engine - Sprite - Keypress event 566
Ring Documentation, Release 1.10 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 } } } # Start the Events Loop 60.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 { 60.22. Using the Game Engine - Sprite - State event 567
Ring Documentation, Release 1.10 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 } } } } # Start the Events Loop 60.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 60.23. Using the Game Engine - Animate - Events 568
Ring Documentation, Release 1.10 # 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 } } 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: 60.23. Using the Game Engine - Animate - Events 569
Ring Documentation, Release 1.10 60.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], 60.24. Using the Game Engine - Map 570
Ring Documentation, Release 1.10 [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: 60.24. Using the Game Engine - Map 571
Ring Documentation, Release 1.10 60.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], [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 60.25. Using the Game Engine - Map Events 572
Ring Documentation, Release 1.10 Screen Shot: 60.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) 60.26. Using the Game Engine - Object and Drawing 573
Ring Documentation, Release 1.10 next } } 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: 60.26. Using the Game Engine - Object and Drawing 574
Ring Documentation, Release 1.10 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 } } 60.26. Using the Game Engine - Object and Drawing 575
Ring Documentation, Release 1.10 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: 60.27 Stars Fighter Game The Stars Fighter source code 60.27. Stars Fighter Game 576
Ring Documentation, Release 1.10 # 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 size = 16 file = "fonts/pirulen.ttf" text = "(C) 2016, Mahmoud Fayed" x = 45 y=140 } 60.27. Stars Fighter Game 577
Ring Documentation, Release 1.10 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 { file = "images/stars.jpg" x = 0 y = 0 point = -370 direction = ge_direction_dec type = ge_type_background 60.27. Stars Fighter Game 578
Ring Documentation, Release 1.10 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 { type = ge_type_fire file = "images/rocket.png" transparent = true x = oself.x + 30 y = oself.y - 30 width = 30 height = 30 point = -30 60.27. Stars Fighter Game 579
Ring Documentation, Release 1.10 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 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 60.27. Stars Fighter Game 580
Ring Documentation, Release 1.10 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 } } } text { animate = false point = 400 size = 30 file = "fonts/pirulen.ttf" text = "Level : " + oGameState.level x = 500 y=90 } } 60.27. Stars Fighter Game 581
Ring Documentation, Release 1.10 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 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 60.27. Stars Fighter Game 582
Ring Documentation, Release 1.10 } } } 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 startplay=false Screen Shot: 60.27. Stars Fighter Game 583
Ring Documentation, Release 1.10 60.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 while true oGameState = New GameState oGame { 60.28. Flappy Bird 3000 Game 584
Ring Documentation, Release 1.10 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 { animate = false size = 25 file = "fonts/pirulen.ttf" text = "Press Space to start" x = 190 y=470 } text { 60.28. Flappy Bird 3000 Game 585
Ring Documentation, Release 1.10 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 func playstart oGame oGame { FPS = 60 FixedFPS = 120 Title = "Flappy Bird 3000" Sprite { 60.28. Flappy Bird 3000 Game 586
Ring Documentation, Release 1.10 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 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 60.28. Flappy Bird 3000 Game 587
Ring Documentation, Release 1.10 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 } if not oGameState.playerwin oGameState.down -- if oGameState.down = 0 oGameState.down = 3 oself { y += 25 if y > 550 y=550 ok } 60.28. Flappy Bird 3000 Game 588
Ring Documentation, Release 1.10 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], [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 60.28. Flappy Bird 3000 Game 589
Ring Documentation, Release 1.10 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: 60.28. Flappy Bird 3000 Game 590
Ring Documentation, Release 1.10 60.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 { title = "Super Man 2016" 60.29. Super Man 2016 Game 591
Ring Documentation, Release 1.10 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" x = 190 y=470 } 60.29. Super Man 2016 Game 592
Ring Documentation, Release 1.10 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 { FPS = 60 FixedFPS = 15 Title = "Super Man 2016" 60.29. Super Man 2016 Game 593
Ring Documentation, Release 1.10 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 state = func ogame,oself { oself { x-=5 y-=5 60.29. Super Man 2016 Game 594
Ring Documentation, Release 1.10 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" height = 123 dotransparent() y -= 40 oGameState.down = 10 if y<=0 y=0 ok 60.29. Super Man 2016 Game 595
Ring Documentation, Release 1.10 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 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) 60.29. Super Man 2016 Game 596
Ring Documentation, Release 1.10 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 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 60.29. Super Man 2016 Game 597
Ring Documentation, Release 1.10 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 func checkgameover ogame if oGameState.gameresult return ok if oGameState.value <= 0 oGameState.value = 0 oGameState.gameresult = true oGame { 60.29. Super Man 2016 Game 598
Ring Documentation, Release 1.10 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 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 60.29. Super Man 2016 Game 599
Ring Documentation, Release 1.10 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 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" } } 60.29. Super Man 2016 Game 600
Ring Documentation, Release 1.10 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 lastcol = 0 playerwin = false DoorKey = false playerindex = 4 value = 1000 moveplayer = false Screen Shot: 60.29. Super Man 2016 Game 601
Ring Documentation, Release 1.10 60.29. Super Man 2016 Game 602
CHAPTER SIXTYONE BUILDING GAMES FOR ANDROID 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. 61.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 61.2 Project Folder Open the project folder : ring/android/ringlibsdl/project 603
Ring Documentation, Release 1.10 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" 61.3 Building the project Move to the ring/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. 61.3. Building the project 604
Ring Documentation, Release 1.10 ant debug 61.3. Building the project 605
CHAPTER SIXTYTWO USING RINGOPENGL AND RINGFREEGLUT FOR 3D GRAPHICS In this chapter we will learn about using RingOpenGL 62.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 62.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 606
Ring Documentation, Release 1.10 • 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" 62.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" 62.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 62.3. What is RingFreeGLUT? 607
Ring Documentation, Release 1.10 62.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) glVertex3f(0.0, 0.0, 0.0) 62.5. Drawing using RingOpenGL 608
Ring Documentation, Release 1.10 glVertex3f(0.5, 0.0, 0.0) glVertex3f(0.5, 0.5, 0.0) glVertex3f(0.0, 0.5, 0.0) glEnd() glColor3f(255,0,0) glBegin(GL_POLYGON) glVertex3f(0.0, 0.0, 0.0) glVertex3f(0.5, 0.0, 0.0) glVertex3f(-0.5,- 1, 0.0) glVertex3f(0.0, -1, 0.0) glEnd() glColor3f(0,0,255) glBegin(GL_POLYGON) glVertex3f(0.0, 0.0, 0.0) glVertex3f(-0.5, 0.0, 0.0) glVertex3f(-0.5,- 0.5, 0.0) glVertex3f(0.0, -0.5, 0.0) glEnd() glFlush() Screen Shot 62.5. Drawing using RingOpenGL 609
Ring Documentation, Release 1.10 62.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 62.6. The First Triangle 610
Ring Documentation, Release 1.10 62.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) 62.7. Window Resize Event 611
Ring Documentation, Release 1.10 // Get Back to the Modelview glMatrixMode(GL_MODELVIEW) 62.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 h = glutEventHeight() w = glutEventWidth() 62.8. Triangle Rotation 612
Ring Documentation, Release 1.10 // 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 62.9 Keyboard Events and Colors Example: load "freeglut.ring" load "opengl21lib.ring" 62.9. Keyboard Events and Colors 613
Ring Documentation, Release 1.10 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 glutSwapBuffers(); func changesize h = glutEventHeight() w = glutEventWidth() // Prevent a divide by zero, when window is too short 62.9. Keyboard Events and Colors 614
Ring Documentation, Release 1.10 // (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 62.9. Keyboard Events and Colors 615
Ring Documentation, Release 1.10 62.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) glTranslatef(0.05, 0.10, 0.18) 62.10. The Camera 616
Ring Documentation, Release 1.10 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 glLoadIdentity() // Set the camera 62.10. The Camera 617
Ring Documentation, Release 1.10 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 glutInit() glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA) 62.10. The Camera 618
Ring Documentation, Release 1.10 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 // 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 62.10. The Camera 619
Ring Documentation, Release 1.10 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() // 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) 62.10. The Camera 620
Ring Documentation, Release 1.10 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() next next glutSwapBuffers() func pressKey key = glutEventKey() xx = glutEventX() 62.10. The Camera 621
Ring Documentation, Release 1.10 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 glEnable(GL_DEPTH_TEST) // enter GLUT event processing cycle glutMainLoop() 62.10. The Camera 622
Ring Documentation, Release 1.10 62.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) func drawSnowMan glColor3f(1.0, 1.0, 1.0) // Draw Body glTranslatef(0.0 ,0.75, 0.0) glutSolidSphere(0.75,20,20) 62.11. Mouse Events 623
Ring Documentation, Release 1.10 // 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) 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() 62.11. Mouse Events 624
Ring Documentation, Release 1.10 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 func mouseButton button = glutEventButton() state = glutEventState() xx = glutEventX() yy = glutEventY() // only start motion if the left button is pressed 62.11. Mouse Events 625
Ring Documentation, Release 1.10 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() 62.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 62.12. Menu Events 626
Ring Documentation, Release 1.10 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 // (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) 62.12. Menu Events 627
Ring Documentation, Release 1.10 // 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 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) 62.12. Menu Events 628
Ring Documentation, Release 1.10 // 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() 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() 62.12. Menu Events 629
Ring Documentation, Release 1.10 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) 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 62.12. Menu Events 630
Ring Documentation, Release 1.10 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) off func processShrinkMenu option = glutEventValue() switch option on C_SHRINK scale = 0.5 on C_NORMAL scale = 1.0 off func processColorMenu option = glutEventValue() 62.12. Menu Events 631
Ring Documentation, Release 1.10 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) 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) 62.12. Menu Events 632
Ring Documentation, Release 1.10 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 62.13 Using Fonts Example: 62.13. Using Fonts 633
Ring Documentation, Release 1.10 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 C_INT_GLUT_BITMAP_HELVETICA_18 = 13 func changeSize w = glutEventWidth() 62.13. Using Fonts 634
Ring Documentation, Release 1.10 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) 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)) 62.13. Using Fonts 635
Ring Documentation, Release 1.10 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) // 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() 62.13. Using Fonts 636
Ring Documentation, Release 1.10 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 // ----------------------------------- // 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 62.13. Using Fonts 637
Ring Documentation, Release 1.10 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 // 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() 62.13. Using Fonts 638
Ring Documentation, Release 1.10 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 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) 62.13. Using Fonts 639
Ring Documentation, Release 1.10 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 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 62.13. Using Fonts 640
Ring Documentation, Release 1.10 62.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 62.14. Frames Per Second 641
Ring Documentation, Release 1.10 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 // 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. 62.14. Frames Per Second 642
Ring Documentation, Release 1.10 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 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) 62.14. Frames Per Second 643
Ring Documentation, Release 1.10 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) 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() 62.14. Frames Per Second 644
Ring Documentation, Release 1.10 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() 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 62.14. Frames Per Second 645
Ring Documentation, Release 1.10 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) 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 62.14. Frames Per Second 646
Ring Documentation, Release 1.10 // ----------------------------------- // MENUS // ----------------------------------- 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() 62.14. Frames Per Second 647
Ring Documentation, Release 1.10 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 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 // ----------------------------------- 62.14. Frames Per Second 648
Ring Documentation, Release 1.10 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) 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 62.14. Frames Per Second 649
Ring Documentation, Release 1.10 The Second screen shot 62.15 Make a Cube using RingOpenGL and RingFreeGLUT Example: load "freeglut.ring" load "opengl21lib.ring" // ---------------------------------------------------------- 62.15. Make a Cube using RingOpenGL and RingFreeGLUT 650
Ring Documentation, Release 1.10 // 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 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 62.15. Make a Cube using RingOpenGL and RingFreeGLUT 651
Ring Documentation, Release 1.10 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 // ---------------------------------------------------------- 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() 62.15. Make a Cube using RingOpenGL and RingFreeGLUT 652
Ring Documentation, Release 1.10 // 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: 62.15. Make a Cube using RingOpenGL and RingFreeGLUT 653
CHAPTER SIXTYTHREE USING RINGOPENGL AND RINGALLEGRO FOR 3D GRAPHICS In this chapter we will learn about using RingOpenGL and RingAllegro 63.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) 654
Ring Documentation, Release 1.10 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) glTexCoord2f(0.0, 1.0) glVertex3f( 1.0, 1.0, 1.0) glTexCoord2f(0.0, 0.0) glVertex3f( 1.0, -1.0, 1.0) 63.1. 3D Cube and Texture 655
Ring Documentation, Release 1.10 // 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() xrot += 0.3 yrot += 0.2 zrot += 0.4 class GraphicsAppBase display event_queue ev timeout timer redraw = true FPS = 60 SCREEN_W = 800 SCREEN_H = 600 KEY_UP = 1 KEY_DOWN = 2 KEY_LEFT = 3 KEY_RIGHT = 4 Key = [false,false,false,false] TITLE = "Graphics Application" func start SetUp() loadResources() eventsLoop() destroy() func setup al_init() 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, 63.1. 3D Cube and Texture 656
Ring Documentation, Release 1.10 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() end func destroy 63.1. 3D Cube and Texture 657
Ring Documentation, Release 1.10 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: 63.2 Many Cubes 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 63.2. Many Cubes 658
Ring Documentation, Release 1.10 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) 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) 63.2. Many Cubes 659
Ring Documentation, Release 1.10 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) 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 63.2. Many Cubes 660
Ring Documentation, Release 1.10 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 GraphicsAppBase display event_queue ev timeout timer redraw = true FPS = 60 SCREEN_W = 800 SCREEN_H = 600 KEY_UP = 1 KEY_DOWN = 2 KEY_LEFT = 3 KEY_RIGHT = 4 Key = [false,false,false,false] TITLE = "Graphics Application" func start SetUp() loadResources() eventsLoop() destroy() func setup al_init() 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() 63.2. Many Cubes 661
Ring Documentation, Release 1.10 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 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() 63.2. Many Cubes 662
Ring Documentation, Release 1.10 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: 63.2. Many Cubes 663
Ring Documentation, Release 1.10 63.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 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 63.3. TicTacToe 3D Game 664
Ring Documentation, Release 1.10 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] ) 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] 63.3. TicTacToe 3D Game 665
Ring Documentation, Release 1.10 [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 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 63.3. TicTacToe 3D Game 666
Ring Documentation, Release 1.10 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 ] ] 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 //horzintal 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 63.3. TicTacToe 3D Game 667
Ring Documentation, Release 1.10 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 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() 63.3. TicTacToe 3D Game 668
Ring Documentation, Release 1.10 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 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() 63.3. TicTacToe 3D Game 669
Ring Documentation, Release 1.10 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 [ 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) 63.3. TicTacToe 3D Game 670
Ring Documentation, Release 1.10 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 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) 63.3. TicTacToe 3D Game 671
Ring Documentation, Release 1.10 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 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() 63.3. TicTacToe 3D Game 672
Ring Documentation, Release 1.10 func loadresources func drawScene func destroyResources func MouseClickEvent exit # Exit from the Events Loop func CloseEvent exit # Exit from the Events Loop Screen Shot: 63.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 63.4. More 3D Samples 673
Ring Documentation, Release 1.10 The next screen shot for the Camera Sample The next screen shot for the Camera and background sample Developer : Azzeddine Remmal 63.4. More 3D Samples 674
Ring Documentation, Release 1.10 63.4. More 3D Samples 675
CHAPTER SIXTYFOUR THE GOLD MAGIC 800 GAME In this chapter we will learn about the Gold Magic 800 Game The game is developed using Ring, RingAllegro and RingOpenGL Steam Page (44 Levels) : https://store.steampowered.com/app/939200/Gold_Magic_800/ Ring comes with a Demo Version (21 Levels Only) You will find the game in ring/applications/goldmagic800 folder 64.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. 64.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. 64.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! 676
Ring Documentation, Release 1.10 64.4 Screen Shots We can select the level The next screen shot for level (1) The Gold Magic 800 Level Editor 64.4. Screen Shots 677
Ring Documentation, Release 1.10 64.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. 64.5. Source Code 678
Ring Documentation, Release 1.10 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 64.5. Source Code 679
CHAPTER SIXTYFIVE DESKTOP AND MOBILE DEVELOPMENT USING RINGQT In this chapter we will learn how to use the Qt framework classes in our Ring applications to create Desktop and Mobile Applications. 65.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()") } btn1 = new qPushButton(win1) { setGeometry(150,200,100,30) settext("Close") setclickevent("pClose()") } lineedit1 = new qLineEdit(win1) { setGeometry(10,100,350,30) } show() } 680
Ring Documentation, Release 1.10 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 65.1. The First GUI Application 681
Ring Documentation, Release 1.10 65.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 stoping 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 65.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) { setGeometry(150,200,100,30) 65.2. The Events Loop 682
Ring Documentation, Release 1.10 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! 65.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) new qtextedit(win1) { setGeometry(10,10,480,480) 65.4. Using the QTextEdit Class 683
Ring Documentation, Release 1.10 } show() } exec() } During the runtime we can paste rich text in the qtextedit widget 65.5 Using the QListWidget Class In this example we will use the QListWidget Class Load "guilib.ring" New qApp { win1 = new qWidget() { 65.5. Using the QListWidget Class 684
Ring Documentation, Release 1.10 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 65.5. Using the QListWidget Class 685
Ring Documentation, Release 1.10 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) settext("Delete item") 65.5. Using the QListWidget Class 686
Ring Documentation, Release 1.10 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 ) } 65.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()) setmodel(ofile) } 65.6. Using QTreeView and QFileSystemModel 687
Ring Documentation, Release 1.10 show() } exec() } The application during the runtime 65.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) layout1 = new qvboxlayout() tree1 = new qtreewidget(win1) { setGeometry(00,00,400,400) 65.7. Using QTreeWidget and QTreeWidgetItem 688
Ring Documentation, Release 1.10 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 65.7. Using QTreeWidget and QTreeWidgetItem 689
Ring Documentation, Release 1.10 65.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 65.8. Using QComboBox Class 690
Ring Documentation, Release 1.10 65.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") } 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") } 65.9. Creating Menubar 691
Ring Documentation, Release 1.10 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) { settext("About") } addaction(oAction) } } show() } exec() } The application during the runtime 65.9. Creating Menubar 692
Ring Documentation, Release 1.10 65.10 Context Menu Example: load "guilib.ring" new qApp { win = new qwidget() { setwindowtitle("Context Menu") resize(400,400) myfilter = new qAllEvents(win) { setContextmenuEvent("mymenu()") } installeventfilter(myfilter) show() } exec() } func mymenu new qMenu(win) { oAction = new qAction(win) { settext("new") SetCLickevent("See :New") 65.10. Context Menu 693
Ring Documentation, Release 1.10 } 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()) } 65.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") 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() } 65.11. Creating Toolbar 694
Ring Documentation, Release 1.10 The application during the runtime 65.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() } 65.12. Creating StatusBar 695
Ring Documentation, Release 1.10 The application during the runtime 65.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) { 65.13. Using QDockWidget 696
Ring Documentation, Release 1.10 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 65.14 Using QTabWidget In this example we will learn about using the QTabWidget class Load "guilib.ring" New qApp { 65.14. Using QTabWidget 697
Ring Documentation, Release 1.10 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") } } 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 65.14. Using QTabWidget 698
Ring Documentation, Release 1.10 65.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() } 65.15. Using QTableWidget 699
Ring Documentation, Release 1.10 exec() } The application during the runtime 65.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 65.16. Using QProgressBar 700
Ring Documentation, Release 1.10 65.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() } exec() } The application during the runtime 65.17. Using QSpinBox 701
Ring Documentation, Release 1.10 65.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() } exec() } The application during the runtime 65.18. Using QSlider 702
Ring Documentation, Release 1.10 65.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() } The application during the runtime 65.19. Using QDateEdit 703
Ring Documentation, Release 1.10 65.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 65.20. Using QDial 704
Ring Documentation, Release 1.10 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()") } pdial = new qdial(win1) { 65.20. Using QDial 705
Ring Documentation, Release 1.10 setGeometry(100,50,250,300) setNotchesVisible(true) setValue(50) SetValueChangedEvent("pDialMove()") } lineedit1 = new qlineedit(win1) { setGeometry(200,400,50,30) setalignment(Qt_AlignHCenter) settext(string(pdial.value())) setreturnPressedEvent("pPress()") } show() } exec() } func pIncrement pdial{val=value()} pdial.setvalue(val+1) lineedit1{settext(string(val+1))} func pDecrement pdial{val=value()} pdial.setvalue(val-1) lineedit1{settext(string(val-1))} func pPress lineedit1{val=text()} pdial.setvalue(number(val)) func pDialMove lineedit1.settext(""+pdial.value()) 65.20. Using QDial 706
Ring Documentation, Release 1.10 65.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() } The application during the runtime 65.21. Using QWebView 707
Ring Documentation, Release 1.10 65.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 65.22. Using QCheckBox 708
Ring Documentation, Release 1.10 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 65.23 Using QRadioButton and QButtonGroup In this example we will learn about using the QRadioButton and QButtonGroup classes Load "guilib.ring" 65.23. Using QRadioButton and QButtonGroup 709
Ring Documentation, Release 1.10 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 65.23. Using QRadioButton and QButtonGroup 710
Ring Documentation, Release 1.10 65.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 65.24. Adding Hyperlink to QLabel 711
Ring Documentation, Release 1.10 65.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") } videowidget4 = new qvideowidget(win1) { 65.25. QVideoWidget and QMediaPlayer 712
Ring Documentation, Release 1.10 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 65.25. QVideoWidget and QMediaPlayer 713
Ring Documentation, Release 1.10 65.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 65.26. Using QFrame 714
Ring Documentation, Release 1.10 65.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()) } 65.27. Display Image using QLabel 715
Ring Documentation, Release 1.10 showMaximized() } exec() } The application during the runtime 65.28 Menubar and StyleSheet Example In this example we will learn about creating menubar and setting the window stylesheet Load "guilib.ring" New qApp { 65.28. Menubar and StyleSheet Example 716
Ring Documentation, Release 1.10 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() } The application during the runtime 65.28. Menubar and StyleSheet Example 717
Ring Documentation, Release 1.10 65.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()") } lineedit1 = new qlineedit(win1) { setGeometry(10,100,350,30) settextchangedevent("pChange()") setreturnpressedevent("penter()") } 65.29. QLineEdit Events and QMessageBox 718
Ring Documentation, Release 1.10 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 65.29. QLineEdit Events and QMessageBox 719
Ring Documentation, Release 1.10 65.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() } 65.30. Other Widgets Events 720
Ring Documentation, Release 1.10 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 65.30. Other Widgets Events 721
Ring Documentation, Release 1.10 65.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 65.31. Using the QTimer Class 722
Ring Documentation, Release 1.10 65.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 BarMan{ setvalue(value() + Increment) } 65.32. Using QProgressBar and Timer 723
Ring Documentation, Release 1.10 Func theTime return "Time : " + Time() 65.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)) PosLeft = (BoxWidth - imageW ) / 2 PosTop = (BoxHeight - imageH ) / 2 65.33. Display Scaled Image using QLabel 724
Ring Documentation, Release 1.10 setGeometry(PosLeft,PosTop,imageW,imageH) } TimerMan = new qtimer(win1) { setinterval(100) ### interval 100 millisecs. settimeoutevent("pTime()") ### ==>> func start() } show() } exec() } ###------------------------------------------------------ ### Fuction 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) 65.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) settext("open file") setclickevent("pOpen()") } show() } 65.34. Using the QFileDialog Class 725
Ring Documentation, Release 1.10 exec() } Func pOpen new qfiledialog(win1) { cName = getopenfilename(win1,"open file","c:","source files(*.ring)") win1.setwindowtitle(cName) } The application during the runtime 65.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) { setgeometry(200,400,100,30) settext("draw") setclickevent("draw()") } show() } 65.35. Drawing using QPainter 726
Ring Documentation, Release 1.10 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 65.35. Drawing using QPainter 727
Ring Documentation, Release 1.10 65.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()") } showmaximized() 65.36. Printing using QPrinter 728
Ring Documentation, Release 1.10 } 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) myweb.show() } system ("test.pdf") system ("test2.pdf") 65.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 printer1 { painter = new qpainter() { 65.37. Using QPrintPreviewDialog 729
Ring Documentation, Release 1.10 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: 65.37. Using QPrintPreviewDialog 730
Ring Documentation, Release 1.10 65.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() { 65.38. Creating More than one Window 731
Ring Documentation, Release 1.10 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 65.39 Playing Sound Example: 65.39. Playing Sound 732
Ring Documentation, Release 1.10 Load "guilib.ring" new qapp { win1 = new qwidget() { setwindowtitle("play sound!") show() } new qmediaplayer() { setmedia(new qurl("footstep.wav")) setvolume(50) play() } exec() } 65.40 Using the QColorDialog Class Example: Load "guilib.ring" oApp = new myapp { start() } Class MyApp oColor win1 Func start 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 65.40. Using the QColorDialog Class 733
Ring Documentation, Release 1.10 65.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() } 65.41. Using qLCDNumber Class 734
Ring Documentation, Release 1.10 The application during the runtime 65.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 65.42. Movable Label Example 735
Ring Documentation, Release 1.10 65.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 65.43. QMessagebox Example 736
Ring Documentation, Release 1.10 65.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") lcheck = exec() 65.44. Using QInputDialog Class 737
Ring Documentation, Release 1.10 if lCheck win1.setwindowtitle(oInput.textvalue()) ok } The application during the runtime 65.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 { SetDialogIcon("notepad.png") msginfo(:Ring,:Welcome) see confirmMsg(:Ring,"Are you sure?") + nl 65.45. Dialog Functions 738
Ring Documentation, Release 1.10 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 } 65.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 65.46. KeyPress and Mouse Move Events 739
Ring Documentation, Release 1.10 65.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()") myfilter.setLeaveevent("pLeave()") 65.47. Moving Objects using the Mouse 740
Ring Documentation, Release 1.10 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 65.47. Moving Objects using the Mouse 741
Ring Documentation, Release 1.10 65.47. Moving Objects using the Mouse 742
Ring Documentation, Release 1.10 65.47. Moving Objects using the Mouse 743
Ring Documentation, Release 1.10 65.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 65.48. Inheritance from GUI Classes 744
Ring Documentation, Release 1.10 65.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 oDesktop = new qDesktopWidget() 65.49. Using QDesktopWidget Class 745
Ring Documentation, Release 1.10 oRect = oDesktop.screenGeometry( oDesktop.primaryScreen() ) win1.move((oRect.width()-win1.width()) /2 , (oRect.Height()-win1.Height())/2 ) win1.show() The application during the runtime 65.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) } new qtimer(win1) { setinterval(50) 65.50. Rotate Text 746
Ring Documentation, Release 1.10 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 65.50. Rotate Text 747
Ring Documentation, Release 1.10 65.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) } setLayout(Layout1) 65.51. Change Focus 748
Ring Documentation, Release 1.10 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 65.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 see "(" + match.capturedStart(1) + "," + match.capturedEnd(1)+ ")" + nl see "(" + match.capturedStart(2) + "," + match.capturedEnd(2)+ ")" + nl see "(" + match.capturedStart(3) + "," + match.capturedEnd(3)+ ")" + nl 65.52. Regular Expressions 749
Ring Documentation, Release 1.10 } } Output Using Regular Expressions dd w+ 1 0 1 11 one ^(dd)/(dd)/(dddd)$ 1 08 12 1985 (0,2) (3,5) (6,10) 65.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()") } lineedit1 = new qtextedit(win1) { setGeometry(150,50,200,300) } win1 { setwindowtitle("client") setgeometry(10,100,400,400) show() 65.53. Simple Client and Server Example 750
Ring Documentation, Release 1.10 } 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) } cOutput = "Server Started" + nl + "listen to port 9999" + nl lineedit1.settext(cOutput) Func pNewConnection oTcpClient = oTcpServer.nextPendingConnection() 65.53. Simple Client and Server Example 751
Ring Documentation, Release 1.10 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 65.54 Dynamic Objects We may create objects in the runtime and add them to windows. Example: load "guilib.ring" oFormDesigner = new FormDesigner { start("oFormDesigner") } Class FormDesigner winToolBox winForm aObjects = [] func start cObjectName oApp = new qApp winToolBox = new qWidget() winToolBox.setWindowTitle("ToolBox") 65.54. Dynamic Objects 752
Ring Documentation, Release 1.10 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 65.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 65.55. Weight History Application 753
Ring Documentation, Release 1.10 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) } 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() } 65.55. Weight History Application 754
Ring Documentation, Release 1.10 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) 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) 65.55. Weight History Application 755
Ring Documentation, Release 1.10 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] 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 65.55. Weight History Application 756
Ring Documentation, Release 1.10 65.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" 65.56. Notepad Application 757
Ring Documentation, Release 1.10 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) { 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") 65.56. Notepad Application 758
Ring Documentation, Release 1.10 } , 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()") } 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()") 65.56. Notepad Application 759
Ring Documentation, Release 1.10 } 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() 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()") 65.56. Notepad Application 760
Ring Documentation, Release 1.10 } 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")) 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") 65.56. Notepad Application 761
Ring Documentation, Release 1.10 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) } } 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() 65.56. Notepad Application 762
Ring Documentation, Release 1.10 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) { 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) { 65.56. Notepad Application 763
Ring Documentation, Release 1.10 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() 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 65.56. Notepad Application 764
Ring Documentation, Release 1.10 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) { 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) { 65.56. Notepad Application 765
Ring Documentation, Release 1.10 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") 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() 65.56. Notepad Application 766
Ring Documentation, Release 1.10 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 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") 65.56. Notepad Application 767
Ring Documentation, Release 1.10 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 new qfiledialog(win1) { cName = getsavefilename(win1,"Save As","","source files(*.ring)") if cName != NULL cActiveFileName = cName writefile(cActiveFileName,textedit1.toplaintext()) status1.showmessage("File : " + cActiveFileName + " saved!",0) pSetActiveFileName() lAskToSave = false ok } func pPrint status1.showmessage("Printing to File : RingDoc.pdf",0) printer1 = new qPrinter(0) { setoutputformat(1) # 1 = pdf setoutputfilename("RingDoc.pdf") textedit1.print(printer1) } status1.showmessage("Done!",0) system("RingDoc.pdf") func pCut textedit1.cut() 65.56. Notepad Application 768
Ring Documentation, Release 1.10 status1.showmessage("Cut!",0) func pCopy textedit1.copy() status1.showmessage("Copy!",0) func pPaste textedit1.paste() status1.showmessage("Paste!",0) func pFont oFontDialog = new qfontdialog() { aFont = getfont() } textedit1.selectall() cFont = aFont[1] pSetFont() Func pSetFont myfont = new qfont("",0,0,0) myfont.fromstring(cFont) textedit1.setcurrentfont(myfont) Func pColor new qcolordialog() { aTextColor = GetColor() } pSetColors() Func pColor2 new qcolordialog() { aBackColor = GetColor() } pSetColors() Func pSetColors textedit1.setstylesheet("color: rgb(" + aTextColor[1] + "," + aTextColor[2] + "," + aTextColor[3] + ");" + "background-color: rgb(" + 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 65.56. Notepad Application 769
Ring Documentation, Release 1.10 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 + "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)) } 65.56. Notepad Application 770
Ring Documentation, Release 1.10 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 The next window for “search and replace” The next screen shot demonstrates the application main window 65.56. Notepad Application 771
Ring Documentation, Release 1.10 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. 65.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) next next 65.57. The Cards Game 772
Ring Documentation, Release 1.10 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 ; background-color: black ;") setclickevent("Page1.win1.close()") } 65.57. The Cards Game 773
Ring Documentation, Release 1.10 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 aStatus[x] = 1 aStatusValues[x] = aValues[nPos] del(aValues,nPos) Player1Eat(x,aStatusValues[x]) checknewgame() 65.57. The Cards Game 774
Ring Documentation, Release 1.10 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 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 65.57. The Cards Game 775
Ring Documentation, Release 1.10 (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 oTest = new qTest oTest.qsleep(nTime) The application during the runtime 65.57. The Cards Game 776
Ring Documentation, Release 1.10 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) 65.57. The Cards Game 777
Ring Documentation, Release 1.10 Note: using Qt we can run the same application on other Mobile systems 65.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() SetRedoAvailableEvent() Continued on next page 65.58. Classes and their Methods to use the default events 778
Ring Documentation, Release 1.10 Table 65.1 – continued from previous page Class Name Methods to use the default Events 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() SetCellDoubleClickedEvent() Continued on next page 65.58. Classes and their Methods to use the default events 779
Ring Documentation, Release 1.10 Table 65.1 – continued from previous page Class Name Methods to use the default Events 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() QTimer SetTimeoutEvent() Continued on next page 65.58. Classes and their Methods to use the default events 780
Ring Documentation, Release 1.10 Table 65.1 – continued from previous page Class Name Methods to use the default Events 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() 65.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. 65.59. Methods to use Events with Events Filter 781
Ring Documentation, Release 1.10 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) 65.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 65.60. The Difference between Qt and RingQt 782
Ring Documentation, Release 1.10 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 65.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. 65.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/applications/formdesigner/tests/indexstart/indexstartView.ring 2. https://github.com/ring-lang/ring/blob/master/applications/formdesigner/tests/indexstart/indexstartController.ring 65.61. RingQt Classes and their Qt Documentation 783
Ring Documentation, Release 1.10 65.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 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 { TD { text("Test" ) } TD { text("30" ) } TD { text("Egypt" ) } 65.63. Creating Reports using the WebLib and the GUILib 784
Ring Documentation, Release 1.10 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) web.show() } system ("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: 65.63. Creating Reports using the WebLib and the GUILib 785
Ring Documentation, Release 1.10 65.63. Creating Reports using the WebLib and the GUILib 786
CHAPTER SIXTYSIX BUILDING RINGQT APPLICATIONS FOR MOBILE In this chapter we will learn about Building RingQt Applications for Mobile. 66.1 Download Requirements Check the next link : http://doc.qt.io/qt-5/androidgs.html Download • 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 66.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 : B:mahmoudToolsJava-Androidadt-bundle-windows-x86-20140702sdk 787
Ring Documentation, Release 1.10 66.3 Install Qt for Android • You can install Qt for Android from the next link https://download.qt.io/archive/qt/5.5/5.5.1/ • Run Qt Creator, Select Tools > Options > Android to add the Android NDK and SDK paths. http://doc.qt.io/qtcreator/creator-developing-android.html 66.4 Using Ring2EXE Starting from Ring 1.6 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 66.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 66.3. Install Qt for Android 788
Ring Documentation, Release 1.10 66.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: 66.6. Comments about developing for Android using RingQt 789
Ring Documentation, Release 1.10 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. 66.6. Comments about developing for Android using RingQt 790
CHAPTER SIXTYSEVEN OBJECTS LIBRARY FOR RINGQT APPLICATION In this chapter we will learn about the objects library for RingQt applications. Ring comes with the Objects library for RingQt applications. Instead of using global variables for windows objects and connecting events to objects using the object name, the Objects Library will manage the GUI objects and will provide a more natural API to quickly create one or many windows from the same class and the 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. The Objects Library is designed to be used with the MVC Design Pattern. The Objects Library is merged in RingQt so you can use it directly when you use RingQt 67.1 Library Usage • Use the Open_Window(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 Last_Window() 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 Open_Window() It will be called. • In the view class, Define the GUI window object as an attribute called win. • You can use Open_WindowNoShow() to avoid displaying the window. • You can use Open_WindowAndLink() to quickly get methods to access the windows. 67.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. 791
Ring Documentation, Release 1.10 • 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 { open_window( :MainWindowController ) exec() } class MainWindowController from WindowsControllerParent oView = new MainWindowView func SubWindowAction Open_window( :SubWindowController ) Last_Window().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 ) ) } resize(400,400) } The next screen shot after creating three sub windows. 67.2. Example 792
Ring Documentation, Release 1.10 The next screen shot after clicking on the button in each sub window. 67.2. Example 793
Ring Documentation, Release 1.10 67.3 Open_WindowAndLink() Function We can use the Open_WindowAndLink() 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/applications/formdesigner/tests/twowindowspart5/firstwindowView.ring 2. https://github.com/ring-lang/ring/blob/master/applications/formdesigner/tests/twowindowspart5/firstwindowController.ring Second Window 1. https://github.com/ring-lang/ring/blob/master/applications/formdesigner/tests/twowindowspart5/secondwindowView.ring 2. https://github.com/ring-lang/ring/blob/master/applications/formdesigner/tests/twowindowspart5/secondwindowController.ring 67.3. Open_WindowAndLink() Function 794
Ring Documentation, Release 1.10 In the next code for example (from FirstWindowController.ring) The Open_WindowAndLink() will create an object from the SecondWindowController Class Then will add the Method : SecondWindow(), IsSecondWindow() Methods to the FirstWindowController Class Also will add the Method : FirstWindow(), 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 Last_Window(), Parent() and SetParentObject() methods. class firstwindowController from windowsControllerParent oView = new firstwindowView func OpenSecondWindow Open_WindowAndLink(:SecondWindowController,self) func SendMessage if IsSecondWindow() SecondWindow().setMessage("Message from the first window") ok func setMessage cMessage oView.Label1.setText(cMessage) 67.4 Open_WindowInPackages() Function The Open_WindowInPackages() function is the same as Open_Window() but takes an extra list that determine the packages to import before opening the window. Syntax: Open_WindowInPackages(cClassName,aPackagesList) Example: The next example from the Form Designer source code, Open the Window Flags window using the open_windowInPackages() function. We determine the class name “WindowFlagsController” and the packages name. The Window Flags window uses the FormDesigner and System.GUI packages. open_windowInPackages(:WindowFlagsController,[ "formdesigner", "System.GUI" ]) 67.5 Objects Library Source Code The library source code is very simple, You can check the source code files • https://github.com/ring-lang/ring/blob/master/extensions/ringqt/objectslib/objects.ring • https://github.com/ring-lang/ring/blob/master/extensions/ringqt/objectslib/subwindows.ring 67.4. Open_WindowInPackages() Function 795
CHAPTER SIXTYEIGHT USING THE FORM DESIGNER 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. 796
Ring Documentation, Release 1.10 68.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. 68.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. 68.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 68.1. The Designer Windows 797
Ring Documentation, Release 1.10 68.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. 68.5 Events Code 1. Just type the method name in the event property. 68.4. Running Forms 798
Ring Documentation, Release 1.10 (2) Then write the method code in the controller class. 68.5. Events Code 799
Ring Documentation, Release 1.10 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 : 68.5. Events Code 800
Ring Documentation, Release 1.10 The Event Code func SayHello oView { LineEdit2.setText("Hello "+ LineEdit1.text() ) } 68.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. 68.7 Menubar Designer From the Window properties we can open the Menubar Designer 68.6. Keyboard Shortcuts 801
Ring Documentation, Release 1.10 68.8 Window Flags From the Window properties we can open the Window Flags window. 68.8. Window Flags 802
Ring Documentation, Release 1.10 68.9 Entering Items For some controls like the List Widget we can enter items separated by comma ‘,’ 68.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. 68.11 More Samples and Tests Check the folder : ring/applications/formdesigner/tests Online : https://github.com/ring-lang/ring/tree/master/applications/formdesigner/tests 68.9. Entering Items 803
CHAPTER SIXTYNINE MULTI-LANGUAGE APPLICATIONS There are many ways to create multi-language Ring application! In this chapter we will learn about using the String2Constant tool 69.1 Using String2Constant Starting from Ring 1.8 we have the String2Constant application You will find this tool in the ring/samples/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. 804
Ring Documentation, Release 1.10 69.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/formdesinger/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 69.2. Form Designer Translation 805
Ring Documentation, Release 1.10 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. 69.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 69.3. Forms Translation 806
Ring Documentation, Release 1.10 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) } 69.3. Forms Translation 807
CHAPTER SEVENTY SCOPE RULES FOR VARIABLES 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 70.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 70.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 808
Ring Documentation, Release 1.10 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 attibutes 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. 70.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). 70.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. 70.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 :- • Global Scope —> Global Scope • Object Scope —> Object Scope 70.3. How Ring find the variable? 809
Ring Documentation, Release 1.10 • 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. 70.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. 70.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 address phone Solution (2) - Use special mark for global variable names like $ 70.6. How Ring Define Variables and Attributes 810
Ring Documentation, Release 1.10 $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() 70.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 70.8. Conflict between Class Attributes and Local Variables 811
Ring Documentation, Release 1.10 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 70.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 ! 70.9. Using Braces to access objects inside Class Methods 812
Ring Documentation, Release 1.10 } 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 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). 70.9. Using Braces to access objects inside Class Methods 813
Ring Documentation, Release 1.10 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 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. 70.9. Using Braces to access objects inside Class Methods 814
Ring Documentation, Release 1.10 70.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 insead 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. 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. 70.10. Accessing the class attributes from braces inside class methods 815
Ring Documentation, Release 1.10 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. 70.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" 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()") } 70.11. Creating a Class for each Window in GUI applications 816
Ring Documentation, Release 1.10 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 ) ) } 70.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 —> Gloabl 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" 70.12. Conflict between self inside braces and self in the class region 817
Ring Documentation, Release 1.10 } 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 attribue 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 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 70.12. Conflict between self inside braces and self in the class region 818
Ring Documentation, Release 1.10 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 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 { 70.12. Conflict between self inside braces and self in the class region 819
Ring Documentation, Release 1.10 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 70.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 70.13. Using braces to escape from the current object scope 820
Ring Documentation, Release 1.10 z: 30.000000 x: 10.000000 y: 20.000000 z: 30.000000 100 200 300 100 200 300 10 20 30 70.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 70.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 70.14. The For Loops uses the local scope 821
Ring Documentation, Release 1.10 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. 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 70.15. Summary of Scope Rules 822
Ring Documentation, Release 1.10 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 { } , 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. 70.15. Summary of Scope Rules 823
CHAPTER SEVENTYONE SCOPE RULES FOR FUNCTIONS 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 71.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. 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. 824
Ring Documentation, Release 1.10 71.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() f2() f3() } myline() Output: 71.2. Example about Sharing Names between Functions and Methods 825
Ring Documentation, Release 1.10 ======================================== 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 ======================================== 71.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 Class myclass func test myline() see "test method" + nl f1() f2() f3() # call f3() method new local { f3() } # call f3() function myline() 71.3. Calling a function sharing the name with a method in the current class 826
Ring Documentation, Release 1.10 func f3 see "f3 method" + nl class local Output: ======================================== test method f1 function f2 function f3 method f3 function ======================================== 71.3. Calling a function sharing the name with a method in the current class 827
CHAPTER SEVENTYTWO SYNTAX FLEXIBILITY In this chapter we will learn about some options that are provided automatically by the Ring compiler for syntax flexibility. 72.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 print "number three" + nl endif endfor 828
Ring Documentation, Release 1.10 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 72.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 changeringoperator plus + changeringkeyword PRINT SEE 72.2. Change Language Operators 829
Ring Documentation, Release 1.10 72.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 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 72.3. Load Syntax Files 830
Ring Documentation, Release 1.10 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. 72.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 72.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: 72.4. Using “()” around the function parameters 831
Ring Documentation, Release 1.10 Hello How are you? Welcome to Ring one two three 72.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 72.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 72.6. Using $ and @ in the start of the variable name 832
Ring Documentation, Release 1.10 72.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 72.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: 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 72.8. Using the ‘else’ keyword as ‘other’ in switch statement 833
Ring Documentation, Release 1.10 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 72.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: 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 { 72.10. Using braces to start and end different control structures 834
Ring Documentation, Release 1.10 x = 1 / 0 catch see "catching error" + nl } Output: if statement.. one for loop.. 12345678910 switch... one try catch... catching error 72.11 Using ‘put’ and ‘get’ as ‘see’ and ‘give’ We can replace the ‘see’ keyword with the ‘put’ keyword. Also we can replacew the ‘give’ keyword with the ‘get’ keyword. Example: put "Hello World" + nl put "Enter Your Name ? " Get Name Put "Hello " + Name 72.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 "thre" + 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 "thre" + nl else put "else" + nl } } 72.11. Using ‘put’ and ‘get’ as ‘see’ and ‘give’ 835
Ring Documentation, Release 1.10 72.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 72.14 Using braces { } in Packages/Classes/Functions Example: load "stdlib.ring" import mypackage new myclass { myfunc() } package mypackage { class myclass { func myfunc { print("Hello, World!n") } } } 72.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 72.13. Using ‘def’ as ‘func’ in functions/methods definition 836
Ring Documentation, Release 1.10 72.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 72.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 72.16. Using ‘endpackage’/’endclass’/’endfunc’ keywords after Packages/Classes/Functions 837
CHAPTER SEVENTYTHREE INTRODUCTION TO THE TYPE HINTS LIBRARY In this chapter we will learn about the Type Hints Library 73.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. 73.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 ; } 73.3 User Types The Type Hints library is very powerful and will support user types (Classes) automatically Example: load "typehints.ring" import mypackage 838
Ring Documentation, Release 1.10 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 } } } 73.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 ; } 73.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 73.4. Using Types inside Code 839
Ring Documentation, Release 1.10 double void # High Level Types string list number object # Other public static abstract protected override 73.5. Rules 840
CHAPTER SEVENTYFOUR COMMAND LINE OPTIONS The ring 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 -w Display Warnings 74.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: =================================================== Tokens - Generated by the Scanner =================================================== 841
Ring Documentation, Release 1.10 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 Keyword : CLASS Identifier : point Identifier : x Identifier : y Identifier : z 74.1. Printing Tokens 842
Ring Documentation, Release 1.10 EndLine =================================================== 74.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 Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Factor --> Number Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic 74.2. Printing Rules 843
Ring Documentation, Release 1.10 Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> 'For' Identifier '=' Expr to Expr ['step' Expr] Line 4 Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus] 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 5 Rule : Next --> 'Next' Line 6 Rule : Mixer -> '(' [Expr { ',' Expr} ] ')' Line 8 Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus] Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> Expr Rule : Statement --> 'Func' Identifier [ParaList] Line 9 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 74.2. Printing Rules 844
Ring Documentation, Release 1.10 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 10 Rule : Factor --> New Identifier {'.' Identifier } Rule : Mixer --> '{' {Statement} BraceEnd Rule : Factor --> Number Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Assignment -> '=' Expr Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus] Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> Expr Rule : Factor --> Number Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Assignment -> '=' Expr Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus] Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot 74.2. Printing Rules 845
Ring Documentation, Release 1.10 Rule : Expr --> LogicNot Rule : Statement --> Expr Rule : Factor --> Number Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Assignment -> '=' Expr Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus] Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> Expr Rule : BraceEnd --> '}' Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Assignment -> '=' Expr Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus] Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> Expr Line 11 Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus] Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift 74.2. Printing Rules 846
Ring Documentation, Release 1.10 Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> 'See' Expr Line 13 Rule : Statement --> 'Class' Identifier Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus] Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> Expr Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus] Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> Expr Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus] Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> Expr =================================================== 74.3 Printing Intermediate Code Command: ring test.ring -ic -norun Output: 74.3. Printing Intermediate Code 847
Ring Documentation, Release 1.10 =================================================== Byte Code - Before Execution by the VM =================================================== PC OPCode Data 1 ReturnNull 2 Func main 3 NewLine 2 4 FuncExE 5 PushC Hello World 6 LoadA nl 0 7 PushV 8 SUM 0 9 Print 10 NewLine 3 11 ExitMark 29 28 12 LoadAFirst x 13 PushN 1.000000 14 BeforeEqual 0 15 Assignment 16 PushN 1.000000 17 StepNumber 18 JumpVarLENum x 10.000000 29 19 NewLine 4 20 FuncExE 21 LoadA x 0 22 PushV 23 LoadA nl 0 24 PushV 25 SUM 0 26 Print 27 NewLine 5 28 IncJump x 18 29 POPExitMark 30 POPStep 31 NewLine 6 32 LoadFunc test 33 Call 0 34 NoOperation 35 NewLine 8 36 PushV 37 FreeStack 38 ReturnNull 39 Func test 40 NewLine 9 41 FuncExE 42 PushC welcome 43 LoadA nl 0 44 PushV 45 SUM 0 46 Print 47 NewLine 10 48 LoadA o1 0 49 AssignmentPointer 50 New point 51 SetScope 52 PushV 74.3. Printing Intermediate Code 848
Ring Documentation, Release 1.10 53 BraceStart 54 LoadA x 0 58 55 AssignmentPointer 56 PushN 10.000000 57 BeforeEqual 0 58 Assignment 0 0 59 FreeStack 60 LoadA y 0 64 61 AssignmentPointer 62 PushN 20.000000 63 BeforeEqual 0 64 Assignment 0 0 65 FreeStack 66 LoadA z 0 70 67 AssignmentPointer 68 PushN 30.000000 69 BeforeEqual 0 70 Assignment 0 0 71 FreeStack 72 LoadFunc ismethod 73 LoadA self 0 74 PushV 75 PushC braceend 76 Call 77 NoOperation 78 PushV 79 JumpZ 85 80 LoadFunc braceend 81 Call 82 NoOperation 83 PushV 84 FreeStack 85 BraceEnd 86 FreeStack 87 NewLine 11 88 FuncExE 89 LoadA o1 0 90 PushV 91 Print 92 NewLine 13 93 ReturnNull 94 Class point 006E8BC0 95 NewLabel 96 LoadA x 0 97 PushV 98 FreeStack 99 LoadA y 0 100 PushV 101 FreeStack 102 LoadA z 0 103 PushV 104 FreeStack 105 ReturnNull =================================================== 74.3. Printing Intermediate Code 849
Ring Documentation, Release 1.10 74.4 Printing Final Intermediate Code Command: ring test.ring -icfinal Output: Hello World 1 2 3 4 5 6 7 8 9 10 welcome x: 10.000000 y: 20.000000 z: 30.000000 =================================================== Byte Code - After Execution by the VM =================================================== PC OPCode Data 1 ReturnNull 2 Func main 3 NewLine 2 4 FuncExE 5 PushC Hello World 6 PushP 007D3670 0 7 PushV 8 SUM 0 9 Print 10 NewLine 3 11 ExitMark 29 28 12 LoadAFirst x 13 PushN 1.000000 14 BeforeEqual 0 15 Assignment 16 PushN 1.000000 17 StepNumber 18 JumpVarLPLENum x 10.000000 29 19 NewLine 4 20 FuncExE 21 PushPLocal x 0 22 PushV 23 PushP 007D3670 0 24 PushV 25 SUM 0 26 Print 27 NewLine 5 74.4. Printing Final Intermediate Code 850
Ring Documentation, Release 1.10 28 IncLPJump x 18 29 POPExitMark 30 POPStep 31 NewLine 6 32 LoadFuncP test 33 Call 0 34 NoOperation 35 NewLine 8 36 PushV 37 FreeStack 38 ReturnNull 39 Func test 40 NewLine 9 41 FuncExE 42 PushC welcome 43 PushP 007D3670 0 44 PushV 45 SUM 0 46 Print 47 NewLine 10 48 PushPLocal o1 0 49 AssignmentPointer 50 New point 51 SetScope 52 PushV 53 BraceStart 54 LoadA x 0 58 55 AssignmentPointer 56 PushN 10.000000 57 BeforeEqual 0 58 SetProperty 0 106 59 FreeStack 60 LoadA y 0 64 61 AssignmentPointer 62 PushN 20.000000 63 BeforeEqual 0 64 SetProperty 0 141 65 FreeStack 66 LoadA z 0 70 67 AssignmentPointer 68 PushN 30.000000 69 BeforeEqual 0 70 SetProperty 0 176 71 FreeStack 72 LoadFunc ismethod 73 LoadA self 0 74 PushV 75 PushC braceend 76 Call 77 NoOperation 78 PushV 79 JumpZ 85 80 LoadFunc braceend 81 Call 82 NoOperation 83 PushV 84 FreeStack 85 BraceEnd 74.4. Printing Final Intermediate Code 851
Ring Documentation, Release 1.10 86 FreeStack 87 NewLine 11 88 FuncExE 89 PushPLocal o1 0 90 PushV 91 Print 92 NewLine 13 93 ReturnNull 94 Class point 007D8470 95 NewLabel 96 LoadA x 0 97 PushV 98 FreeStack 99 LoadA y 0 100 PushV 101 FreeStack 102 LoadA z 0 103 PushV 104 FreeStack 105 ReturnNull 106 LoadFunc ismethod 107 LoadA ring_gettemp_var 0 108 PushV 109 PushC setx 110 Call 0 111 NoOperation 112 PushV 113 JumpZ 132 114 NewLine 2 115 LoadA ring_gettemp_var 0 116 LoadMethod setx 117 LoadA ring_settemp_var 0 118 PushV 119 Call 0 1 120 AfterCallMethod 121 PushV 122 FreeStack 123 NewLine 3 124 LoadA ring_tempflag_var 0 128 125 AssignmentPointer 126 PushN 0.000000 127 BeforeEqual 0 128 Assignment 0 0 129 FreeStack 130 NewLine 4 131 Jump 140 132 NewLine 5 133 PushP 007D37D8 0 137 134 AssignmentPointer 135 PushN 1.000000 136 BeforeEqual 0 137 Assignment 0 0 138 FreeStack 139 NewLine 6 140 Return 141 LoadFunc ismethod 142 LoadA ring_gettemp_var 0 143 PushV 74.4. Printing Final Intermediate Code 852
Ring Documentation, Release 1.10 144 PushC sety 145 Call 0 146 NoOperation 147 PushV 148 JumpZ 167 149 NewLine 2 150 LoadA ring_gettemp_var 0 151 LoadMethod sety 152 LoadA ring_settemp_var 0 153 PushV 154 Call 0 1 155 AfterCallMethod 156 PushV 157 FreeStack 158 NewLine 3 159 LoadA ring_tempflag_var 0 163 160 AssignmentPointer 161 PushN 0.000000 162 BeforeEqual 0 163 Assignment 0 0 164 FreeStack 165 NewLine 4 166 Jump 175 167 NewLine 5 168 PushP 007D37D8 0 172 169 AssignmentPointer 170 PushN 1.000000 171 BeforeEqual 0 172 Assignment 0 0 173 FreeStack 174 NewLine 6 175 Return 176 LoadFunc ismethod 177 LoadA ring_gettemp_var 0 178 PushV 179 PushC setz 180 Call 0 181 NoOperation 182 PushV 183 JumpZ 202 184 NewLine 2 185 LoadA ring_gettemp_var 0 186 LoadMethod setz 187 LoadA ring_settemp_var 0 188 PushV 189 Call 0 1 190 AfterCallMethod 191 PushV 192 FreeStack 193 NewLine 3 194 LoadA ring_tempflag_var 0 198 195 AssignmentPointer 196 PushN 0.000000 197 BeforeEqual 0 198 Assignment 0 0 199 FreeStack 200 NewLine 4 201 Jump 210 74.4. Printing Final Intermediate Code 853
Ring Documentation, Release 1.10 202 NewLine 5 203 PushP 007D37D8 0 207 204 AssignmentPointer 205 PushN 1.000000 206 BeforeEqual 0 207 Assignment 0 0 208 FreeStack 209 NewLine 6 210 Return =================================================== 74.5 CGI Support Command: ring test.ring -cgi 74.6 No Run Command: ring test.ring -norun 74.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! 74.8 Performance Command: 74.5. CGI Support 854
Ring Documentation, Release 1.10 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 9 10 welcome x: 10.000000 y: 20.000000 z: 30.000000 =================================================== Date : 2015/09/15 Time : 15:56:17 Clock : 0 =================================================== 74.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 74.9. Generate Object File 855
CHAPTER SEVENTYFIVE PERFORMANCE TIPS In this chapter we will learn more about the Ring performance. 75.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 856
Ring Documentation, Release 1.10 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: 75.1. Introduction 857
Ring Documentation, Release 1.10 75.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: 75.2. Creating Lists 858
Ring Documentation, Release 1.10 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 75.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 75.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" ? "Using len() before the For loop" t1 = clock() nMax = len(aList) 75.3. Arithmetic Operations 859
Ring Documentation, Release 1.10 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. 75.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: 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. 75.5. Calling Functions and Methods 860
Ring Documentation, Release 1.10 Note: Using the dot operator to call methods is faster than using braces. 75.5. Calling Functions and Methods 861
CHAPTER SEVENTYSIX DISTRIBUTING RING APPLICATIONS 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! 76.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. 76.2 Protecting the Source Code Step 1: Execute the next command ring myapp.ring -go 862
Ring Documentation, Release 1.10 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. 76.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) 76.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 76.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. 76.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. 76.3. The files ring.ring and ring.ringo 863
CHAPTER SEVENTYSEVEN DISTRIBUTING RING APPLICATIONS USING 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 and Mobile devices Note: We can use the Distribute Menu in the Ring Notepad application (More Easy) 77.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 ge generated by the Visual C/C++ Linker) filename (Executable File - On Linux & MacOS X platforms) 77.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. So it’s better and easy to have a C compiler on your machine to be used by Ring2EXE. 864
Ring Documentation, Release 1.10 77.3 Example We have test.ring contains the next code see "Hello, World!" + nl To build th executable file for Windows, Linux or macOS ring2exe test.ring To run the program (Windows) test To run the program (Linux and macOS) ./test 77.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 -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 -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 77.3. Example 865
Ring Documentation, Release 1.10 77.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 77.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 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 77.5. Building standalone console application 866
Ring Documentation, Release 1.10 77.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 77.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 77.7. Distributing RingQt Applications 867
Ring Documentation, Release 1.10 77.9 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) 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! 77.10 Building the Weight History Application for Mobile using RingQt Another example to distribute your application for Mobile Devices using Ring2EXE and Qt 77.9. Building the Cards Game for Mobile using RingQt 868
Ring Documentation, Release 1.10 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 <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. 77.11 Building the Form Designer for Mobile using RingQt To build the Form Designer application (ring/applications/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 77.11. Building the Form Designer for Mobile using RingQt 869
Ring Documentation, Release 1.10 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> <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/applications/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")) 77.11. Building the Form Designer for Mobile using RingQt 870
Ring Documentation, Release 1.10 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") } ] tool1 = win.addtoolbar("files") { for x in aBtns { addwidget(x) addseparator() } } From this example, We know that we can use sub folders for images. 77.12 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! 77.13 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 77.12. Creating the Qt resource file using Folder2qrc 871
Ring Documentation, Release 1.10 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/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/ring2exe/libs 77.13. Important Information about Ring2EXE 872
CHAPTER SEVENTYEIGHT THE RING PACKAGE MANAGER (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. 78.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 78.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 registred packages. ringpm search [keywords...] Example: ringpm search notepad Output: Package : ringnotepad (Ring Notepad) Package : notepadppeditorextension (Notepad++ Editor Extension package) 873
Ring Documentation, Release 1.10 To print all packages in the RingPM Registry, use the search command without keywords. Example: ringpm search 78.3 Updating the RingPM Registry The RingPM Registry is a local copy of all registred 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) 78.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 ringpm run firstpackage 78.3. Updating the RingPM Registry 874
Ring Documentation, Release 1.10 To install a package in the current folder Example (5) : ringpm install 78.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 78.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 To run a package in the current folder Example(4): ringpm run 78.5. Printing List of Installed Packages 875
Ring Documentation, Release 1.10 78.7 Update Package We can update a package using the Update command ringpm update <packagename> Example: ringpm update ringnotepad 78.8 Remove Package We can remove a package using the Remove command ringpm remove <packagename> Example: ringpm remove ringnotepad 78.9 Deleting All Packages We can delete all packages using the Format command Example: ringpm format 78.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 • 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" 78.7. Update Package 876
Ring Documentation, Release 1.10 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 = [ ], :macosfiles = [ ], :windowsringfolderfiles = [ ], :linuxringfolderfiles = [ 78.10. Creating New Package 877
Ring Documentation, Release 1.10 ], :ubunturingfolderfiles = [ ], :fedoraringfolderfiles = [ ], :macosringfolderfiles = [ ], :run = "ring main.ring", :windowsrun = "", :linuxrun = "", :macosrun = "", :ubunturun = "", :fedorarun = "", :setup = "", :windowssetup = "", :linuxsetup = "", :macossetup = "", :ubuntusetup = "", :fedorasetup = "", :remove = "", :windowsremove = "", :linuxremove = "", :macosremove = "", :ubunturemove = "", :fedoraremove = "" ] 78.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 Desciption 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) 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 Continued on next page 78.11. The Package Description File 878
Ring Documentation, Release 1.10 Table 78.1 – continued from previous page Attribute Description 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 78.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 aPackageInfo = [ :name = "The RingNotepad Package", :description = "Our RingNotepad package using the Ring programming language", :folder = "ringnotepad", :developer = "Mahmoud Fayed", :email = "msfclipper@yahoo.com", :license = "MIT License", :version = "1.0.0", :ringversion = "1.10", :versions = [ [ 78.12. Create Package in the Current Folder 879
Ring Documentation, Release 1.10 :version = "1.0.0", :branch = "master" ] ], :libs = [ [ :name = "stdlib", :version = "1.0", :providerusername = "" ], [ :name = "ringqt", :version = "1.0", :providerusername = "" ], [ :name = "findinfiles", :version = "1.0", :providerusername = "" ], [ :name = "formdesigner", :version = "1.0", :providerusername = "" ], [ :name = "libdepwin_apache", :version = "1.0", :providerusername = "" ] ], :files = [ "main.ring", "README.md" ], :ringfolderfiles = [ "applications/rnote/batch/killwebserver.bat", "applications/rnote/batch/run.bat", "applications/rnote/batch/run2.bat", "applications/rnote/image/back.jpg", "applications/rnote/image/back2.jpg", "applications/rnote/image/close.png", "applications/rnote/image/colors.png", "applications/rnote/image/copy.png", "applications/rnote/image/cut.png", "applications/rnote/image/debug.png", "applications/rnote/image/font.png", "applications/rnote/image/formdesigner.png", "applications/rnote/image/new.png", "applications/rnote/image/notepad.png", "applications/rnote/image/open.png", "applications/rnote/image/paste.png", "applications/rnote/image/print.png", "applications/rnote/image/project.png", "applications/rnote/image/richtext.png", "applications/rnote/image/run.png", "applications/rnote/image/rungui.png", "applications/rnote/image/save.png", 78.12. Create Package in the Current Folder 880
Ring Documentation, Release 1.10 "applications/rnote/image/saveas.png", "applications/rnote/image/search.png", "applications/rnote/image/source.png", "applications/rnote/image/undo.png", "applications/rnote/image/web.png", "applications/rnote/README.md", "applications/rnote/rnote.ring", "applications/rnote/rnoteactivefile.ring", "applications/rnote/rnoteactivefolder.ring", "applications/rnote/rnoteautocomplete.ring", "applications/rnote/rnotebase.ring", "applications/rnote/rnotecontroller.ring", "applications/rnote/rnotedistribute.ring", "applications/rnote/rnoteeditmenu.ring", "applications/rnote/rnoteeditorevents.ring", "applications/rnote/rnotefilemenu.ring", "applications/rnote/rnotefiles.ring", "applications/rnote/rnotefilestabs.ring", "applications/rnote/rnotefind.ring", "applications/rnote/rnotefindinfiles.ring", "applications/rnote/rnoteformdesigner.ring", "applications/rnote/rnotegoto.ring", "applications/rnote/rnotehelp.ring", "applications/rnote/rnotelists.ring", "applications/rnote/rnotemainfiletoolbar.ring", "applications/rnote/rnotemainwindow.ring", "applications/rnote/rnotemode.ring", "applications/rnote/rnoteoutputwindow.ring", "applications/rnote/rnoteprogrammenu.ring", "applications/rnote/rnoterun.ring", "applications/rnote/rnotesettings.ring", "applications/rnote/rnotestyle.ring", "applications/rnote/rnotetabwidth.ring", "applications/rnote/rnotetools.ring", "applications/rnote/rnotetreeviewevents.ring", "applications/rnote/rnoteviewmenu.ring", "applications/rnote/rnotewebbrowser.ring" ], :run = "ring main.ring" ] 78.13 The RingPM Registry File The RingPM Registry is a local copy of all registred 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 78.13. The RingPM Registry File 881
Ring Documentation, Release 1.10 • 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/ringpm/registry/registry.ring 78.13. The RingPM Registry File 882
CHAPTER SEVENTYNINE LOW LEVEL FUNCTIONS In this chapter we will learn about the low level functions provided by Ring • callgc() • varptr() • space() • nullpointer() • object2pointer() • pointer2object() • ispointer() • ptrcmp() • ringvm_cfunctionslist() • ringvm_functionslist() • ringvm_classeslist() • ringvm_packageslist() • ringvm_memorylist() • ringvm_calllist() • ringvm_fileslist() • ringvm_settrace() • ringvm_tracedata() • ringvm_traceevent() • ringvm_tracefunc() • ringvm_scopescount() • ringvm_evalinscope() • ringvm_passerror() • ringvm_hideerrorMsg() • ringvm_callfunc() • ringvm_see() • ringvm_give() 883
Ring Documentation, Release 1.10 • ringvm_info() 79.1 callgc() function Use this function to force calling the garbage collector during function execution when you use a loop that create temp. variables that you don’t free using the assignment operation. It’s very rare to need this function but it’s useful when you create something like event-loop for your game engine and start creating lists on the fly when you call functions. Example While True # process events # call functions using temp. lists like myfunc(["temp list"]) # call the garbage collector callgc() End Tip: In Ring the garbage collector works automatically in the end of function execution or when you use the assign- ment statement. 79.2 varptr() function Use the varptr() function when you need to pass a pointer to a C/C++ function. Syntax: varptr(cVariableName,cPointerType) —> Low Level Object (C Pointer) example: r = 10 z = 20 see r + nl see varptr("r","int") see varptr("z","int") Output: 10 00E3C740 int 2 00E3BEC0 int 2 Note: the low level object is a list contains three items (The Pointer, The Type, The Status) 79.1. callgc() function 884
Ring Documentation, Release 1.10 79.3 space() function Use the space function to allocate a specific number of bytes in Memory. Syntax: Space(nBytesCount) ---> String Example: mystring = space(200) See "String Size : " + len(mystring) + nl See "String : " + mystring + nl See "String Pointer : " See varptr("mystring","char *") Output: String Size : 200 String : String Pointer : 00FF8FE8 char * 2 Note: You may need the space() and VarPtr() functions to pass buffers to C functions. 79.4 nullpointer() function You may need to pass the NULL pointer to a C function that may expect a pointer as parameter and accept NULL pointers for optional parameters. Example: The next example uses the SDL_BlitSurface() function from the LibSDL Library through RingSDL The function accept SDL_Rect pointers in the second and the last parameter. Also the function accept NULL pointers, so we can pass them using the NULLPointer() Function. SDL_BlitSurface(text, nullpointer(), surface, nullpointer()) Note: The previous code doesn’t work alone, you need to learn how to use RingSDL first. Tip: We can pass NULL as parameter instead of using NULLPointer() 79.5 object2pointer() function Use this function to get a C pointer for Ring lists and objects Syntax: object2pointer(List|Object) --> Low Level Object ( C Pointer ) 79.3. space() function 885
Ring Documentation, Release 1.10 79.6 pointer2object() function Use this function to get the Ring list and/or object from the low level object (C Pointer) Syntax: pointer2object(Low Level Object) ---> List|Object Example: # Create the list mylist = 1:5 # Create pointer to the list x = object2pointer(mylist) see x see nl # Add items to the list mylist + "welcome" # print the list items y = pointer2object(x) see y Output: 0069A5D8 OBJECTPOINTER 0 1 2 3 4 5 welcome Note: In Ring the assignment operator copy lists and objects by value, to copy by reference Just use the ob- ject2pointer() and pointer2object() functions. Tip: The object2pointer() and pointer2object() are used in the stdlib - Tree Class implementation to create a reference for the parent node (object) in the child node (another object). 79.7 ispointer() function Check if the parameter is a pointer (C Object) or not. Syntax: IsPointer(vPara) ---> True|False Example : 79.6. pointer2object() function 886
Ring Documentation, Release 1.10 fp = fopen(filename(),"r") ? type(fp) ? ispointer(fp) Output : file 1 79.8 ptrcmp() function We can compare between two pointers (C Objects) using the ptrcmp() function. Syntax: ptrcmp(oObject1,oObject2) ---> value = 1 if oObject1 = oObject2 value = 0 if oObject1 != oObject2 Example: fp = fopen("ptrcmp.ring","r") fp2 = fp fp3 = fopen("ptrcmp.ring","r") see ptrcmp(fp,fp2) + nl see ptrcmp(fp,fp3) + nl fclose(fp) fclose(fp3) Output: 1 0 79.9 ringvm_cfunctionslist() function The Function return a list of functions written in C. Syntax: RingVM_CFunctionsList() ---> List Example: See RingVM_CFunctionsList() 79.10 ringvm_functionslist() function The Function return a list of functions written in Ring. Each List Member is a list contains the next items 79.8. ptrcmp() function 887
Ring Documentation, Release 1.10 • Function Name • Program Counter (PC) - Function Position in Byte Code. • Source Code File Name • Private Flag (For Private Methods in Classes) Syntax: RingVM_FunctionsList() ---> List Example: test() func test see ringvm_functionslist() Output: test 8 B:/ring/tests/scripts/functionslist.ring 0 79.11 ringvm_classeslist() function The Function return a list of Classes. Each List Member is a list contains the next items • Class Name • Program Counter (PC) - Class Position in Byte Code. • Parent Class Name • Methods List • Flag (Is parent class information collected) • Pointer to the package (or NULL if no package is used) Syntax: RingVM_ClassesList() ---> List Example: see ringvm_classeslist() class class1 func f1 class class2 from class1 class class3 from class1 Output: class1 9 79.11. ringvm_classeslist() function 888
Ring Documentation, Release 1.10 f1 13 B:/ring/tests/scripts/classeslist.ring 0 0 00000000 class2 16 class1 0 00000000 class3 20 class1 0 00000000 79.12 ringvm_packageslist() function The Function return a list of Packages. Each List Member is a list contains the next items • Package Name • Classes List Syntax: RingVM_PackagesList() ---> List Example: see ringvm_packageslist() package package1 class class1 package package2 class class1 package package3 class class1 Output: package1 class1 11 0 00FEF838 package2 class1 17 0 00FEF978 79.12. ringvm_packageslist() function 889
Ring Documentation, Release 1.10 package3 class1 23 0 00FEFF68 79.13 ringvm_memorylist() function The Function return a list of Memory Scopes and Variables. Each List Member is a list contains variables in a different scope. Each Item in the scope list is a list contains the next items • Variable Name • Variable Type • Variable Value • Pointer Type (List/Item) if the value is a list • Private Flag (if the variable is an attribute in a Class) Syntax: RingVM_MemoryList() ---> List Example: x = 10 test() func test y = 20 see ringvm_memorylist() Output: true 2 1 0 0 false 2 0 0 0 nl 1 0 0 null 1 0 0 79.13. ringvm_memorylist() function 890
Ring Documentation, Release 1.10 ring_gettemp_var 4 00000000 0 0 ccatcherror 1 NULL 0 0 ring_settemp_var 4 00000000 0 0 ring_tempflag_var 2 0 0 0 stdin 3 50512DB8 file 0 0 0 stdout 3 50512DD8 file 0 0 0 stderr 3 50512DF8 file 0 0 0 this 4 00000000 0 0 sysargv 3 B:ringbin/ring B:/ring/tests/scripts/memorylist.ring 0 0 x 2 10 0 0 y 79.13. ringvm_memorylist() function 891
Ring Documentation, Release 1.10 2 20 0 0 79.14 ringvm_calllist() function The Function return a list of the functions call list. Each List Member is a list contains the next items • Function Type • Function Name • Program Counter (PC) • Stack Pointer (SP) • Temp. Memory List • Method or Function Flag • Caller PC • FuncExec Flag • ListStart Flag • Nested Lists Pointer • State List Syntax: RingVM_CallList() ---> List Example: hello() func hello test() func test mylist = ringvm_calllist() for t in mylist see t[2] + nl next Output: function hello() in file B:/ring/tests/scripts/calllist.ring called from line 1 function test() in file B:/ring/tests/scripts/calllist.ring called from line 3 ringvm_calllist 79.15 ringvm_fileslist() function Function return a list of the Ring Files. 79.14. ringvm_calllist() function 892
Ring Documentation, Release 1.10 Syntax: RingVM_FilesList() ---> List Example: load "stdlib.ring" see ringvm_fileslist() Output: B:/ring/tests/scripts/fileslist.ring B:ringbinstdlib.ring eval stdlib.ring stdlib.rh stdclasses.ring stdfunctions.ring stdbase.ring stdstring.ring stdlist.ring stdstack.ring stdqueue.ring stdmath.ring stddatetime.ring stdfile.ring stdsystem.ring stddebug.ring stddatatype.ring stdconversion.ring stdodbc.ring stdmysql.ring stdsecurity.ring stdinternet.ring stdhashtable.ring stdtree.ring 79.16 ringvm_settrace() The function ringvm_settrace() determine the Trace function name The trace function is a Ring function that will be called for each event Syntax: RingVM_SetTrace(cCode) 79.17 ringvm_tracedata() Inside the function that we will use for tracing events We can use the ringvm_tracedata() function to get the event data. The event data is a list contains the next items • The Source Code Line Number 79.16. ringvm_settrace() 893
Ring Documentation, Release 1.10 • The Source File Name • The Function/Method Name • Method or Function (Bool : True=Method, False=Function/File) Syntax: RingVM_TraceData() ---> aDataList 79.18 ringvm_traceevent() Inside the function that we will use for tracing events We can use ringvm_traceevent() to know the event type • New Line • Before Function • After Function • Runtime Error • Before C Function • After C Function Syntax: RingVM_TraceEvent() ---> nTraceEvent 79.19 ringvm_tracefunc() The function return the name of the function that we are using for tracing events. Syntax: RingVM_TraceEvent() ---> cCode 79.20 ringvm_scopescount() We can use the RingVM_ScopesCount() function to know the number of scopes used in the application. In the start of the program, We have the (global scope only) When we call a function, A new scope is created. When the function execution is done, the function scope is deleted. Syntax: RingVM_ScopesCount() ---> nScopes 79.18. ringvm_traceevent() 894
Ring Documentation, Release 1.10 79.21 ringvm_evalinscope() The function ringvm_evalinscope() is similar to the eval() function Unlike eval() which execute the code in the current scope Using RingVM_EvalInScope() we can execute the scope in a specific scope. Syntax: RingVM_EvalInScope(nScope,cCode) 79.22 ringvm_passerror() When we have runtime error, After printing the Error message, Ring will end the execution of the program. Using ringvm_passerror() we can avoid that, and continue the execution of our program. Syntax: RingVM_PassError() 79.23 ringvm_hideerrormsg() We can disable/enable displaying the runtime error messages using the RingVM_HideErrorMsg() function. Syntax: RingVM_HideErrorMsg(lStatus) 79.24 ringvm_callfunc() We can call a function from a string without using eval() using the ringvm_callfunc() Syntax: RingVM_CallFunc(cFuncName) 79.25 Example - Using the Trace Functions The next example use the Trace Functions to trace the program Events! In practical, We will use the Trace Library instead of these low level functions! load "tracelib.ring" ringvm_settrace("mytrace()") see "Hello, world!" + nl see "Welcome" + nl see "How are you?" +nl mytest() 79.21. ringvm_evalinscope() 895
Ring Documentation, Release 1.10 new myclass { mymethod() } func mytest see "Message from mytest" + nl func mytrace see "====== The Trace function is Active ======" + nl + "Trace Function Name : " + ringvm_TraceFunc() + nl + "Trace Event : " switch ringvm_TraceEvent() on TRACEEVENT_NEWLINE see "New Line" on TRACEEVENT_NEWFUNC see "New Function" on TRACEEVENT_RETURN see "Return" on TRACEEVENT_ERROR see "Error" on TRACEEVENT_BEFORECFUNC see "Before C Function" on TRACEEVENT_AFTERCFUNC see "After C Function" off see nl + "Line Number : " + ringvm_tracedata()[TRACEDATA_LINENUMBER] + nl + "File Name : " + ringvm_tracedata()[TRACEDATA_FILENAME] + nl + "Function Name : " + ringvm_tracedata()[TRACEDATA_FUNCNAME] + nl + "Method or Function : " if ringvm_tracedata()[TRACEDATA_METHODORFUNC] = TRACEDATA_METHODORFUNC_METHOD see "Method" else if ringvm_tracedata()[TRACEDATA_FUNCNAME] = NULL see "Command" else see "Function" ok ok see nl + Copy("=",42) + nl class myclass func mymethod see "Message from mymethod" + nl Output: ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : After C Function Line Number : 3 File Name : test1.ring Function Name : ringvm_settrace Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 5 File Name : test1.ring Function Name : Method or Function : Command ========================================== Hello, world! ====== The Trace function is Active ====== 79.25. Example - Using the Trace Functions 896
Ring Documentation, Release 1.10 Trace Function Name : mytrace() Trace Event : New Line Line Number : 6 File Name : test1.ring Function Name : Method or Function : Command ========================================== Welcome ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 7 File Name : test1.ring Function Name : Method or Function : Command ========================================== How are you? ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 8 File Name : test1.ring Function Name : Method or Function : Command ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Function Line Number : 8 File Name : test1.ring Function Name : mytest Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 12 File Name : test1.ring Function Name : mytest Method or Function : Function ========================================== Message from mytest ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 14 File Name : test1.ring Function Name : mytest Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : Return Line Number : 8 File Name : test1.ring Function Name : Method or Function : Command ========================================== 79.25. Example - Using the Trace Functions 897
Ring Documentation, Release 1.10 ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 9 File Name : test1.ring Function Name : Method or Function : Command ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 43 File Name : test1.ring Function Name : Method or Function : Command ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : Before C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : After C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Function Line Number : 9 File Name : test1.ring Function Name : mymethod Method or Function : Method ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 44 File Name : test1.ring Function Name : mymethod Method or Function : Method ========================================== Message from mymethod ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : Return Line Number : 9 File Name : test1.ring Function Name : Method or Function : Command ========================================== ====== The Trace function is Active ====== 79.25. Example - Using the Trace Functions 898
Ring Documentation, Release 1.10 Trace Function Name : mytrace() Trace Event : Before C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : After C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : Before C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : After C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 11 File Name : test1.ring Function Name : Method or Function : Command ========================================== 79.26 Example - The Trace Library The next example uses the Trace functions provided by the Ring language to create the Trace library. Using the Trace library we have nice Tracing tools and Interaction debugger too. # Trace Events TRACEEVENT_NEWLINE = 1 TRACEEVENT_NEWFUNC = 2 TRACEEVENT_RETURN = 3 TRACEEVENT_ERROR = 4 TRACEEVENT_BEFORECFUNC = 5 TRACEEVENT_AFTERCFUNC = 6 # Trace Data TRACEDATA_LINENUMBER = 1 79.26. Example - The Trace Library 899
Ring Documentation, Release 1.10 TRACEDATA_FILENAME = 2 TRACEDATA_FUNCNAME = 3 TRACEDATA_METHODORFUNC = 4 # Method of Function TRACEDATA_METHODORFUNC_METHOD = TRUE TRACEDATA_METHODORFUNC_NOTMETHOD = FALSE TRACE_BREAKPOINTS = TRUE TRACE_TEMPLIST = [] func Trace cType switch trim(lower(cType)) on :AllEvents ringvm_settrace("TraceLib_AllEvents()") on :Functions ringvm_settrace("TraceLib_Functions()") on :PassError ringvm_settrace("TraceLib_PassError()") on :Debugger ringvm_settrace("TraceLib_Debugger()") on :LineByLine ringvm_settrace("TraceLib_LineByLine()") off func TraceLib_AllEvents if right(ringvm_tracedata()[TRACEDATA_FILENAME],13) = "tracelib.ring" return ok see "====== The Trace function is Active ======" + nl + "Trace Function Name : " + ringvm_TraceFunc() + nl + "Trace Event : " switch ringvm_TraceEvent() on TRACEEVENT_NEWLINE see "New Line" on TRACEEVENT_NEWFUNC see "New Function" on TRACEEVENT_RETURN see "Return" on TRACEEVENT_ERROR see "Error" on TRACEEVENT_BEFORECFUNC see "Before C Function" on TRACEEVENT_AFTERCFUNC see "After C Function" off see nl + "Line Number : " + ringvm_tracedata()[TRACEDATA_LINENUMBER] + nl + "File Name : " + ringvm_tracedata()[TRACEDATA_FILENAME] + nl + "Function Name : " + ringvm_tracedata()[TRACEDATA_FUNCNAME] + nl + "Method or Function : " if ringvm_tracedata()[TRACEDATA_METHODORFUNC] = TRACEDATA_METHODORFUNC_METHOD see "Method" else if ringvm_tracedata()[TRACEDATA_FUNCNAME] = NULL see "Command" else see "Function" ok ok see nl + Copy("=",42) + nl 79.26. Example - The Trace Library 900
Ring Documentation, Release 1.10 func TraceLib_Functions if right(ringvm_tracedata()[TRACEDATA_FILENAME],13) = "tracelib.ring" return ok switch ringvm_TraceEvent() on TRACEEVENT_NEWFUNC see "Open Func : " + ringvm_TraceData()[TRACEDATA_FUNCNAME] + nl on TRACEEVENT_RETURN see "Return to Func : " + ringvm_TraceData()[TRACEDATA_FUNCNAME] + nl off func TraceLib_PassError if right(ringvm_tracedata()[TRACEDATA_FILENAME],13) = "tracelib.ring" return ok switch ringvm_TraceEvent() on TRACEEVENT_ERROR see nl see "TraceLib : After Error !" + nl ringvm_passerror() off func TraceLib_Debugger if right(ringvm_tracedata()[TRACEDATA_FILENAME],13) = "tracelib.ring" return ok switch ringvm_TraceEvent() on TRACEEVENT_ERROR _BreakPoint() off func TraceLib_LineByLine if right(ringvm_tracedata()[TRACEDATA_FILENAME],13) = "tracelib.ring" or ringvm_TraceEvent() != TRACEEVENT_NEWLINE return ok aList = ringvm_tracedata() see "Before Line : " + aList[TRACEDATA_LINENUMBER] + nl _BreakPoint() func BreakPoint if not TRACE_BREAKPOINTS return ok _BreakPoint() func _BreakPoint see nl+nl+Copy("=",60) + nl + Copy(" ",20)+"Interactive Debugger" + nl + Copy("=",60) + nl + "Command (Exit) : End Program" + nl + "Command (Cont) : Continue Execution" + nl + "Command (Locals) : Print local variables names" + nl + "Command (LocalsData) : Print local variables data" + nl + "Command (Globals) : Print global variables names" + nl + "We can execute Ring code" + nl + 79.26. Example - The Trace Library 901
Ring Documentation, Release 1.10 Copy("=",60) + nl while true see nl + "code:> " give cCode cmd = trim(lower(cCode)) if cmd = "exit" or cmd = "bye" shutdown() ok nScope = ringvm_scopescount()-2 switch cmd on "locals" ringvm_EvalInScope(nScope,"see locals() callgc()") loop on "localsdata" PrintLocalsData(nScope) loop on "globals" ringvm_EvalInScope(nScope,"see globals() callgc()") loop on "cont" ringvm_passerror() exit off Try ringvm_EvalInScope(nScope,cCode) catch see cCatchError done end func NoBreakPoints TRACE_BREAKPOINTS = FALSE func PrintLocalsData nScope if nScope = 1 # Global ringvm_Evalinscope(nScope,'TRACE_TEMPLIST = globals()') else ringvm_Evalinscope(nScope,'TRACE_TEMPLIST = locals() callgc()') ok see nl aTempList = TRACE_TEMPLIST TRACE_TEMPLIST = [] nSpaces = 5 for TRACE_ITEM in aTempList if len(TRACE_ITEM) + 5 > nSpaces nSpaces = len(TRACE_ITEM) + 5 ok next for TRACE_ITEM in aTempList see "Variable : " + TRACE_ITEM cVarName = TRACE_ITEM see copy(" ",nSpaces-len(cVarName)) + " Type : " ringvm_Evalinscope(nScope,"see type(" + TRACE_ITEM +")") ringvm_Evalinscope(nScope,"see Copy(' ',fabs(15-len(type(" + TRACE_ITEM +"))))") see " Value : " ringvm_Evalinscope(nScope,"see " + TRACE_ITEM) 79.26. Example - The Trace Library 902
Ring Documentation, Release 1.10 see nl next 79.27 ringvm_see() function Using the ringvm_see() function we can redefine the behavior of the See command Also we can use ring_see() to have the original behavior Example: see "Hello world" + nl see 123 + nl see ["one","two","three"] see new point {x=10 y=20 z=30} func ringvm_see t ring_see("We want to print: ") ring_See(t) class point x y z Output: We want to print: Hello world We want to print: 123 We want to print: one two three We want to print: x: 10.000000 y: 20.000000 z: 30.000000 79.28 ringvm_give() function Using the ringvm_give() function we can redefine the behavior of the Give command Example: see "Name: " give name see "Hello " + name func ringvm_give see "Mahmoud" + nl return "Mahmoud" Output: Name: Mahmoud Hello Mahmoud 79.29 ringvm_info() function The ringvm_info() is an internal function that return a list of information about the Ring VM structure. 79.27. ringvm_see() function 903
Ring Documentation, Release 1.10 It’s used only by the Ring Team in advanced tests to check the VM status. Syntax: ringvm_info() ---> List of information about the VM structure 79.29. ringvm_info() function 904
CHAPTER EIGHTY THE TRACE LIBRARY AND THE INTERACTIVE DEBUGGER In this chapter we will learn about the Trace Library and the Interactive Debugger 80.1 Loading the Trace library To start using the Trace library, We must load it first! load "tracelib.ring" 80.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 80.3 Trace control flow between functions The next example demonstrates the Trace library usage to trace the control flow between functions. Trace(:Functions) test1() 905
Ring Documentation, Release 1.10 func test1 see :test1 + nl test2() func test2 see :test2 + nl see test3() + nl func test3 see :test3 + nl return "test 3 output" 80.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!" 80.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 80.6 Execute Program Line by Line The next example demonstrates the Trace library usage to execute the program line by line! Trace(:LineByLine) test1() 80.4. Pass Error 906
Ring Documentation, Release 1.10 func test1 x = 10 see :test1 + nl t = 12 test2() see "After Error!" +nl see "t = " + t + nl 80.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 80.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 80.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 80.7. BreakPoint 907
Ring Documentation, Release 1.10 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 80.9. Using the Interactive Debugger 908
Ring Documentation, Release 1.10 We can run the Interactive Debugger in the Output Window 80.9. Using the Interactive Debugger 909
CHAPTER EIGHTYONE EMBEDDING RING IN RING In this chapter we will learn about embedding Ring in Ring programs and applications. 81.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 10 20 910
Ring Documentation, Release 1.10 81.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') 81.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() } exec() } func test pState = ring_state_init() ring_state_runcode(pstate,"load 'guilib.ring'") ring_state_runcode(pState,"x = NULL") # Pass String 81.2. Serial Execution of Programs 911
Ring Documentation, Release 1.10 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 enviroment ring_state_runcode(pState," new qWidget { pObject = x setwindowtitle('Message from the Sub Ring Environment') } ") ring_state_delete(pState) 81.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 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() 81.4. ring_state_new() and ring_state_mainfile() 912
Ring Documentation, Release 1.10 } 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! 81.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! 81.5. Runtime Errors when Embedding Ring in Ring 913
CHAPTER EIGHTYTWO EXTENSION USING THE C/C++ LANGUAGES We can extend the Ring Virtual Machine (RingVM) by adding new functions written in the C programming language or C++. The RingVM comes with many functions written in C that we can call like any Ring function. We can extend the language by writing new functions then rebuilding the RingVM again, or we can create shared library (DLL/So) file to extend the RingVM without the need to rebuild it. The Ring language source code comes with two files to add new modules to the RingVM, ring_ext.h and ring_ext.c 82.1 ring_ext.h The file ring_ext.h contains constants that we can change to include/exclude modules during the build process. #ifndef ringext_h #define ringext_h /* Constants */ #define RING_VM_LISTFUNCS 1 #define RING_VM_REFMETA 1 #define RING_VM_MATH 1 #define RING_VM_FILE 1 #define RING_VM_OS 1 #define RING_VM_MYSQL 1 #define RING_VM_ODBC 1 #define RING_VM_OPENSSL 1 #define RING_VM_CURL 1 #define RING_VM_DLL 1 #endif 82.2 ring_ext.c The file ring_ext.c check constants defined in ring_ext.h before calling the start-up function in each module. Each module contains a function that register the module functions in the RingVM. #include "ring.h" void ring_vm_extension ( RingState *pRingState ) { /* Reflection and Meta-programming */ #if RING_VM_REFMETA ring_vm_refmeta_loadfunctions(pRingState); #endif 914
Ring Documentation, Release 1.10 /* List Functions */ #if RING_VM_LISTFUNCS ring_vm_listfuncs_loadfunctions(pRingState); #endif /* Math */ #if RING_VM_MATH ring_vm_math_loadfunctions(pRingState); #endif /* File */ #if RING_VM_FILE ring_vm_file_loadfunctions(pRingState); #endif /* OS */ #if RING_VM_OS ring_vm_os_loadfunctions(pRingState); #endif /* MySQL */ #if RING_VM_MYSQL ring_vm_mysql_loadfunctions(pRingState); #endif /* ODBC */ #if RING_VM_ODBC ring_vm_odbc_loadfunctions(pRingState); #endif /* OPENSSL */ #if RING_VM_OPENSSL ring_vm_openssl_loadfunctions(pRingState); #endif /* CURL */ #if RING_VM_CURL ring_vm_curl_loadfunctions(pRingState); #endif /* DLL */ #if RING_VM_DLL ring_vm_dll_loadfunctions(pRingState); #endif } 82.3 Module Organization Each module starts by include the ring header file (ring.h). This files contains the Ring API that we can use to extend the RingVM. Each module comes with a function to register the module functions in the RingVM The registration is done by using ring_vm_funcregister() function. The ring_vm_funcregister() function takes two parameters, the first is the function name that will be used by Ring programs to call the function. The second parameter is the function pointer in the C program. for example, the ring_vmmath.c module contains the next code to register the module functions #include "ring.h" void ring_vm_math_loadfunctions ( RingState *pRingState ) { ring_vm_funcregister("sin",ring_vm_math_sin); ring_vm_funcregister("cos",ring_vm_math_cos); 82.3. Module Organization 915
Ring Documentation, Release 1.10 ring_vm_funcregister("tan",ring_vm_math_tan); ring_vm_funcregister("asin",ring_vm_math_asin); ring_vm_funcregister("acos",ring_vm_math_acos); ring_vm_funcregister("atan",ring_vm_math_atan); ring_vm_funcregister("atan2",ring_vm_math_atan2); ring_vm_funcregister("sinh",ring_vm_math_sinh); ring_vm_funcregister("cosh",ring_vm_math_cosh); ring_vm_funcregister("tanh",ring_vm_math_tanh); ring_vm_funcregister("exp",ring_vm_math_exp); ring_vm_funcregister("log",ring_vm_math_log); ring_vm_funcregister("log10",ring_vm_math_log10); ring_vm_funcregister("ceil",ring_vm_math_ceil); ring_vm_funcregister("floor",ring_vm_math_floor); ring_vm_funcregister("fabs",ring_vm_math_fabs); ring_vm_funcregister("pow",ring_vm_math_pow); ring_vm_funcregister("sqrt",ring_vm_math_sqrt); ring_vm_funcregister("unsigned",ring_vm_math_unsigned); ring_vm_funcregister("decimals",ring_vm_math_decimals); ring_vm_funcregister("murmur3hash",ring_vm_math_murmur3hash); } Tip: Remember that the function ring_vm_math_loadfunctions() will be called by the ring_vm_extension() function (in the ring_ext.c file). 82.4 Function Structure Each module function may contains the next steps 1 - Check Parameters Count 2 - Check Parameters Type 3 - Get Parameters Values 4 - Execute Code/Call Functions 5 - Return Value The structure is very similar to any function (Input - Process - Output) But here we will use the Ring API for the steps 1,2,3 and 5. 82.5 Check Parameters Count We can check the parameters count using the RING_API_PARACOUNT macro. We can compare RING_API_PARACOUNT with any numeric value using == or != operators. Example: if ( RING_API_PARACOUNT != 1 ) { /* code */ } Example: 82.4. Function Structure 916
Ring Documentation, Release 1.10 if ( RING_API_PARACOUNT == 1 ) { /* code */ } 82.6 Display Error Message We can display error messages using the RING_API_ERROR() function. The function will display the error and end the execution of the program. Note: the behaviour of this function can be changed by the Ring code using Try/Catch/Done statements, so in your C code, use Return after this function. Syntax: RING_API_ERROR(const char *cErrorMsg); The Ring API comes with some of predefined error messages that we can use #define RING_API_MISS1PARA "Bad parameters count, the function expect one parameter" #define RING_API_MISS2PARA "Bad parameters count, the function expect two parameters" #define RING_API_MISS3PARA "Bad parameters count, the function expect three parameters" #define RING_API_MISS4PARA "Bad parameters count, the function expect four parameters" #define RING_API_BADPARATYPE "Bad parameter type!" #define RING_API_BADPARACOUNT "Bad parameters count!" #define RING_API_BADPARARANGE "Bad parameters value, error in range!" #define RING_API_NOTPOINTER "Error in parameter, not pointer!" #define RING_API_NULLPOINTER "Error in parameter, NULL pointer!" #define RING_API_EMPTYLIST "Bad parameter, empty list!" 82.7 Check Parameters Type We can check the parameter type using the next functions int RING_API_ISNUMBER(int nParameterNumber); int RING_API_ISSTRING(int nParameterNumber); int RING_API_ISLIST(int nParameterNumber); int RING_API_ISPOINTER(int nParameterNumber); The output of these functions will be 1 (True) or 0 (False). 82.8 Get Parameters Values We can get paramters values using the next functions double RING_API_GETNUMBER(int nParameterNumber); const char *RING_API_GETSTRING(int nParameterNumber); int RING_API_GETSTRINGSIZE(int nParameterNumber); List *RING_API_GETLIST(int nParameterNumber); void *RING_API_GETCPOINTER(int nParameterNumber, const char *cPoinerType); int RING_API_GETPOINTERTYPE(int nParameterNumber); 82.6. Display Error Message 917
Ring Documentation, Release 1.10 82.9 Return Value We can return values from our function using the next functions. RING_API_RETNUMBER(double nValue); RING_API_RETSTRING(const char *cString); RING_API_RETSTRING2(const char *cString,int nStringSize); RING_API_RETLIST(List *pList); RING_API_RETCPOINTER(void *pValue,const char *cPointerType); RING_API_RETMANAGEDCPOINTER(void *pValue,const char *cPointerType, void (* pFreeFunc)(void *,void *)) 82.10 Function Prototype When we define new function to be used for RingVM extension, we use the next prototype void my_function_name( void *pPointer ); or we can use the RING_FUNC() Macro RING_FUNC(my_function_name); 82.11 Sin() Function Implementation The next code represents the sin() function implementation using the Ring API and the sin() C function. void ring_vm_math_sin ( void *pPointer ) { if ( RING_API_PARACOUNT != 1 ) { RING_API_ERROR(RING_API_MISS1PARA); return ; } if ( RING_API_ISNUMBER(1) ) { RING_API_RETNUMBER(sin(RING_API_GETNUMBER(1))); } else { RING_API_ERROR(RING_API_BADPARATYPE); } } 82.12 Fopen() and Fclose() Functions Implementation The next code represents the fopen() function implementation using the Ring API and the fopen() C Function. The function takes two parameters, the first parameter is the file name as string. The second parameter is the mode as string. In the file ring_vmfile.h we have some constants to use as the pointer type like #define RING_VM_POINTER_FILE "file" #define RING_VM_POINTER_FILEPOS "filepos" The function implementation in ring_vmfile.c 82.9. Return Value 918
Ring Documentation, Release 1.10 void ring_vm_file_fopen ( void *pPointer ) { FILE *fp ; if ( RING_API_PARACOUNT != 2 ) { RING_API_ERROR(RING_API_MISS2PARA); return ; } if ( RING_API_ISSTRING(1) && RING_API_ISSTRING(2) ) { fp = fopen(RING_API_GETSTRING(1),RING_API_GETSTRING(2)); RING_API_RETCPOINTER(fp,RING_VM_POINTER_FILE); } else { RING_API_ERROR(RING_API_BADPARATYPE); } } The next code represents the fclose() function implementation void ring_vm_file_fclose ( void *pPointer ) { FILE *fp ; if ( RING_API_PARACOUNT != 1 ) { RING_API_ERROR(RING_API_MISS1PARA); return ; } if ( RING_API_ISPOINTER(1) ) { fp = (FILE *) RING_API_GETCPOINTER(1,RING_VM_POINTER_FILE) ; if ( fp != NULL ) { RING_API_RETNUMBER(fclose(fp)); RING_API_SETNULLPOINTER(1); } } else { RING_API_ERROR(RING_API_BADPARATYPE); } } From fopen() and fclose() implementation we learned 1 - how to return C pointer using RING_API_RETCPOINTER() function 2 - how to check if the parameter is a pointer using the RING_API_ISPOINTER() function 3 - how to get C pointer value using the RING_API_GETCPOINTER() function 4 - how to set the C pointer variable (in RingVM) to NULL using the RING_API_SETNULLPOINTER() function 82.13 Ring API - List Functions In this section we will learn about the list functions provided by the Ring API to create new lists and manipulate the list items. List * ring_list_new ( int nSize ) ; void ring_list_newitem ( List *pList ) ; Item * ring_list_getitem ( List *pList,int index ) ; List * ring_list_delete ( List *pList ) ; void ring_list_deleteitem ( List *pList,int index ) ; void ring_list_print ( List *pList ) ; int ring_list_gettype ( List *pList, int index ) ; void ring_list_setint ( List *pList, int index ,int number ) ; 82.13. Ring API - List Functions 919
Ring Documentation, Release 1.10 void ring_list_addint ( List *pList,int x ) ; void ring_list_setpointer ( List *pList, int index ,void *pValue ) ; void ring_list_addpointer ( List *pList,void *pValue ) ; void ring_list_setfuncpointer ( List *pList, int index ,void (*pFunc)(void *) ) ; void ring_list_addfuncpointer ( List *pList,void (*pFunc)(void *) ) ; int ring_list_isfuncpointer ( List *pList, int index ) ; void ring_list_setdouble ( List *pList, int index ,double number ) ; void ring_list_adddouble ( List *pList,double x ) ; void ring_list_setstring ( List *pList, int index ,const char *str ) ; void ring_list_setstring2 ( List *pList, int index ,const char *str,int nStrSize ) ; void ring_list_addstring ( List *pList,const char *str ) ; void ring_list_addstring2 ( List *pList,const char *str,int nStrSize ) ; List * ring_list_newlist ( List *pList ) ; List * ring_list_getlist ( List *pList, int index ) ; void ring_list_setlist ( List *pList, int index ) ; void ring_list_setactiveitem ( List *pList, Items *pItems, int index ) ; void ring_list_copy ( List *pNewList, List *pList ) ; int ring_list_isnumber ( List *pList, int index ) ; int ring_list_isstring ( List *pList, int index ) ; int ring_list_islist ( List *pList, int index ) ; int ring_list_ispointer ( List *pList, int index ) ; void ring_list_deleteallitems ( List *pList ) ; void ring_list_insertitem ( List *pList,int x ) ; void ring_list_insertint ( List *pList,int nPos,int x ) ; void ring_list_insertdouble ( List *pList,int nPos,double x ) ; void ring_list_insertpointer ( List *pList,int nPos,void *pValue ) ; void ring_list_insertstring ( List *pList,int nPos,const char *str ) ; void ring_list_insertstring2 ( List *pList,int nPos,const char *str,int nStrSize ) ; void ring_list_insertfuncpointer ( List *pList,int nPos,void (*pFunc)(void *) ) ; List * ring_list_insertlist ( List *pList,int nPos ) ; int ring_list_isiteminsidelist ( List *pList,Item *pItem ) ; int ring_list_findstring ( List *pList,const char *str,int nColumn ) ; int ring_list_finddouble ( List *pList,double nNum1,int nColumn ) ; void ring_list_sortnum ( List *pList,int left,int right,int nColumn ) ; void ring_list_sortstr ( List *pList,int left,int right,int nColumn ) ; int ring_list_binarysearchnum ( List *pList,double nNum1,int nColumn ) ; int ring_list_binarysearchstr ( List *pList,const char *cFind,int nColumn ) ; void ring_list_swap ( List *pList,int x,int y ) ; double ring_list_getdoublecolumn ( List *pList,int nIndex,int nColumn ) ; char * ring_list_getstringcolumn ( List *pList,int nIndex,int nColumn ) ; void ring_list_genarray ( List *pList ) ; void ring_list_deletearray ( List *pList ) ; void ring_list_genhashtable ( List *pList ) ; void ring_list_genhashtable2 ( List *pList ) ; void ring_list_refcopy ( List *pNewList, List *pList ) ; void ring_list_clear ( List *pList ) ; /* Macro */ ring_list_isdouble(pList,index) ring_list_isint(pList,index) ring_list_deletelastitem(x) ring_list_gethashtable(x) ring_list_getint(pList,index) ring_list_getpointer(pList,index) ring_list_getfuncpointer(pList,index) ring_list_callfuncpointer(pList,index,x) ring_list_getdouble(pList,index) ring_list_getstring(pList,index) ring_list_getstringobject(pList,index) 82.13. Ring API - List Functions 920
Ring Documentation, Release 1.10 ring_list_getstringsize(pList,index) ring_list_getsize(x) (x->nSize) 82.14 Ring API - String Functions In this section we will learn about the string functions provided by the Ring API to create new string and manipulate the string content. String * ring_string_new ( const char *str ) ; String * ring_string_new2 ( const char *str,int nStrSize ) ; String * ring_string_delete ( String *pString ) ; int ring_string_size ( String *pString ) ; void ring_string_set ( String *pString,const char *str ) ; void ring_string_set2 ( String *pString,const char *str,int nStrSize ) ; void ring_string_add ( String *pString,const char *str ) ; void ring_string_add2 ( String *pString,const char *str,int nStrSize ) ; void ring_string_print ( String *pString ) ; void ring_string_setfromint ( String *pString,int x ) ; char * ring_string_lower ( char *cStr ) ; char * ring_string_upper ( char *cStr ) ; char * ring_string_lower2 ( char *cStr,int nStrSize ) ; char * ring_string_upper2 ( char *cStr,int nStrSize ) ; char * ring_string_find ( char *cStr1,char *cStr2 ) ; char * ring_string_find2 ( char *cStr1,int nStrSize1,char *cStr2,int nStrSize2 ) ; /* Macro */ ring_string_tolower(x) ring_string_toupper(x) ring_string_get(x) 82.15 MySQL_Columns() Function Implementation The next code presents the MySQL_Columns() function implementation. This function returns table columns information. void ring_vm_mysql_columns ( void *pPointer ) { MYSQL *con ; MYSQL_RES *result ; int nColumns,x ; MYSQL_ROW row ; MYSQL_FIELD *field ; List *pList, *pList2 ; if ( RING_API_PARACOUNT != 1 ) { RING_API_ERROR(RING_API_MISS1PARA); return ; } if ( RING_API_ISPOINTER(1) ) { con = (MYSQL *) RING_API_GETCPOINTER(1,RING_VM_POINTER_MYSQL) ; if ( con == NULL ) { return ; } result = mysql_store_result(con); if ( result == NULL ) { 82.14. Ring API - String Functions 921
Ring Documentation, Release 1.10 RING_API_RETNUMBER(0); return ; } pList = RING_API_NEWLIST ; nColumns = mysql_num_fields(result); if ( row = mysql_fetch_row(result) ) { while ( field = mysql_fetch_field(result) ) { pList2 = ring_list_newlist(pList); ring_list_addstring(pList2,field->name); ring_list_adddouble(pList2,field->length); ring_list_adddouble(pList2,field->type); ring_list_adddouble(pList2,field->flags); } } mysql_free_result(result); RING_API_RETLIST(pList); } else { RING_API_ERROR(RING_API_BADPARATYPE); } } Lists are of type List, in the previoud function we declared two pointers of type List using List *pList, *pList2; Note: The function uses RING_API_NEWLIST to create new list instead of ring_list_new() to create the list in Temp. Memory related to the function scope. This way we can return the list from the function. Also we don’t delete the list, if it’s stored in a variable by Ring Code it will be saved, if not it will be automatically deleted by RingVM. The list can contains sub lists, we used the function ring_list_newlist() to create a sublist. The function ring_list_addstring() is used to add string items to the list/sublist. The function ring_list_adddouble() is used to add numeric items to the list/sublist. Note: All numeric items in lists returned from RingVM extension functions must be of type double and added to the list using ring_list_adddouble() function. We return the list from the extension function using the RING_API_RETLIST() function. 82.16 Dynamic/Shared Libraries (DLL/So/Dylib) and LoadLib() func- tion Instead of rebuilding the RingVM after writing new functions using C/C++ and the Ring API, we can create a DLL/So/Dylib file and dynamically use the functions provided by this file in the runtime using the LoadLib() function. Dynamic library example in C #include "ring.h" RING_DLL __declspec(dllexport) RING_FUNC(ring_ringlib_dlfunc) { printf("Message from dlfunc"); } 82.16. Dynamic/Shared Libraries (DLL/So/Dylib) and LoadLib() function 922
Ring Documentation, Release 1.10 RING_DLL void ringlib_init(RingState *pRingState) { ring_vm_funcregister("dlfunc",ring_ringlib_dlfunc); } the idea is to create the ringlib_init() function, this function will be called by the RingVM when we use the generated DLL file though the LoadLib() function. Inside the ringlib_init() function we can register the module function or call a function that do the registration process for all of the module functions. The next Ring code demonstrates how to use the DLL library during the runtime. See "Dynamic DLL" + NL LoadLib("ringlib.dll") dlfunc() Output: Dynamic DLL Message from dlfunc 82.17 Using RING_API_RETMANAGEDCPOINTER() Using RING_API_RETMANAGEDCPOINTER() the Ring extensions written in C/C++ languages can return a man- aged pointer to Ring. This pointer can be controlled by the Ring VM using reference counting. This is important to avoid the need to write code that free the unmanaged resources like QPixMap objects in RingQt. Also the Code Generator for extensions is updated to automatically use RING_API_RETMANAGEDCPOINTER() based on need. Syntax: RING_API_RETMANAGEDCPOINTER(void *pValue,const char *cPointerType, void (* pFreeFunc)(void *,void *)) Example: The next example from ring_qt.cpp - QPixMap Class - Scaled() Method. RING_FUNC(ring_QPixmap_scaled) { QPixmap *pObject ; if ( RING_API_PARACOUNT != 5 ) { RING_API_ERROR(RING_API_BADPARACOUNT); return ; } RING_API_IGNORECPOINTERTYPE ; if ( ! RING_API_ISPOINTER(1) ) { RING_API_ERROR(RING_API_BADPARATYPE); return ; } pObject = (QPixmap *) RING_API_GETCPOINTER(1,"QPixmap"); if ( ! RING_API_ISNUMBER(2) ) { RING_API_ERROR(RING_API_BADPARATYPE); return ; } if ( ! RING_API_ISNUMBER(3) ) { 82.17. Using RING_API_RETMANAGEDCPOINTER() 923
Ring Documentation, Release 1.10 RING_API_ERROR(RING_API_BADPARATYPE); return ; } if ( ! RING_API_ISNUMBER(4) ) { RING_API_ERROR(RING_API_BADPARATYPE); return ; } if ( ! RING_API_ISNUMBER(5) ) { RING_API_ERROR(RING_API_BADPARATYPE); return ; } { QPixmap *pValue ; pValue = new QPixmap() ; *pValue = pObject->scaled( (int ) RING_API_GETNUMBER(2), (int ) RING_API_GETNUMBER(3), (Qt::AspectRatioMode ) (int) RING_API_GETNUMBER(4), (Qt::TransformationMode ) (int) RING_API_GETNUMBER(5)); RING_API_RETMANAGEDCPOINTER(pValue,"QPixmap",ring_QPixmap_freefunc); } } The function that will free the memory takes two parameters (Ring State and the allocated Memory Pointer) Example: void ring_QPixmap_freefunc(void *pState,void *pPointer) { QPixmap *pObject ; pObject = (QPixmap *) pPointer; delete pObject ; } 82.17. Using RING_API_RETMANAGEDCPOINTER() 924
CHAPTER EIGHTYTHREE EMBEDDING RING LANGUAGE IN C/C++ PROGRAMS We can use the Ring language from C/C++ programs using the next functions RingState *ring_state_init(); ring_state_runcode(RingState *pState,const char *cCode); ring_state_delete(RingState *pState); 83.1 Ring State The idea is to use the ring_state_init() to create new state for the Ring Language then call the ring_state_runcode() function to execut Ring code using the same state. When we are done, we call the ring_state_delete() to free the memory. Example: #include "ring.h" #include "stdlib.h" int main(int argc, char *argv[]) { RingState *pState = ring_state_init(); printf("welcomen"); ring_state_runcode(pState,"see 'hello world from the ring programming language'+nl"); ring_state_delete(pState); } Output: welcome hello world from the ring programming language 83.2 Ring State Functions The Ring API comes with the next functions to create and delete the state. Also we have functions to create new variables and get variables values. RingState * ring_state_init ( void ) ; RingState * ring_state_delete ( RingState *pRingState ) ; void ring_state_runcode ( RingState *pRingState,const char *cStr ) ; List * ring_state_findvar ( RingState *pRingState,const char *cStr ) ; List * ring_state_newvar ( RingState *pRingState,const char *cStr ) ; void ring_state_main ( int argc, char *argv[] ) ; 925
Ring Documentation, Release 1.10 void ring_state_runfile ( RingState *pRingState,const char *cFileName ) ; void ring_state_runobjectfile ( RingState *pRingState,const char *cFileName ) ; 83.3 Ring State Variables We can create more than one ring state in the same program and we can create and modify variable values. To get the variable list we can use the ring_state_findvar() function. To create new variable we can use the ring_state_newvar() function. Example: #include "ring.h" #include "stdlib.h" int main(int argc, char *argv[]) { List *pList; RingState *pState = ring_state_init(); RingState *pState2 = ring_state_init(); printf("welcomen"); ring_state_runcode(pState,"see 'hello world from the ring programming language'+nl"); printf("Again from C we will call ring coden"); ring_state_runcode(pState,"for x = 1 to 10 see x + nl next"); ring_state_runcode(pState2,"for x = 1 to 5 see x + nl next"); printf("Now we will display the x variable value from ring coden"); ring_state_runcode(pState,"see 'x value : ' + x + nl "); ring_state_runcode(pState2,"see 'x value : ' + x + nl "); pList = ring_state_findvar(pState,"x"); printf("Printing Ring variable value from C , %.0fn", ring_list_getdouble(pList,RING_VAR_VALUE)); printf("now we will set the ring variable value from Cn"); ring_list_setdouble(pList,RING_VAR_VALUE,20); ring_state_runcode(pState,"see 'x value after update : ' + x + nl "); pList = ring_state_newvar(pState,"v1"); ring_list_setdouble(pList,RING_VAR_VALUE,10); pList = ring_state_newvar(pState,"v2"); ring_list_setdouble(pList,RING_VAR_VALUE,20); ring_state_runcode(pState,"see 'v1 + v2 = ' see v1+v2 see nl"); ring_state_runcode(pState,"see 'end of test' + nl"); ring_state_delete(pState); 83.3. Ring State Variables 926
Ring Documentation, Release 1.10 ring_state_delete(pState2); } Output: welcome hello world from the ring programming language Again from C we will call ring code 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 Now we will display the x variable value from ring code x value : 11 x value : 6 Printing Ring variable value from C , 11 now we will set the ring variable value from C x value after update : 20 v1 + v2 = 30 end of test 83.3. Ring State Variables 927
CHAPTER EIGHTYFOUR CODE GENERATOR FOR WRAPPING C/C++ LIBRARIES In this chapter we will learn how to use the code generator to wrap C/C++ Libraries to use it in our Ring applications. 84.1 Using the tool The code generator program is parsec.ring that can be executed as any ring code using the ring language. URL : https://github.com/ring-lang/ring/tree/master/extensions/codegen for example to read a configuration file called test.cf to generate the source code file test.c run parsec.ring as in the next command ring parsec.ring test.cf test.c 84.2 Configuration file The configuration file (*.cf) is the input file that we pass to the code generator. This file determine the functions prototypes that we need to use from a C/C++ library. Writing configuration files is simple according to the next rules 84.3 Using the function prototype • To generate code that wraps a C function, we just write the C function prototype Example: ALLEGRO_DISPLAY *al_create_display(int w, int h) void al_destroy_display(ALLEGRO_DISPLAY *display) int al_get_new_display_flags(void) void al_set_new_display_flags(int flags) int al_get_new_display_option(int option, int *importance) The previous example will guide the code generator to generate 5 functions that wraps the al_create_display(), al_destroy_display(), al_get_new_display_flags(), al_set_new_diplay_flas() and al_get_new_display_option() func- tions. The generated code will be as in the next example 928
Ring Documentation, Release 1.10 RING_FUNC(ring_al_create_display) { if ( RING_API_PARACOUNT != 2 ) { RING_API_ERROR(RING_API_MISS2PARA); return ; } if ( ! RING_API_ISNUMBER(1) ) { RING_API_ERROR(RING_API_BADPARATYPE); return ; } if ( ! RING_API_ISNUMBER(2) ) { RING_API_ERROR(RING_API_BADPARATYPE); return ; } RING_API_RETCPOINTER(al_create_display( (int ) RING_API_GETNUMBER(1), (int ) RING_API_GETNUMBER(2)),"ALLEGRO_DISPLAY"); } RING_FUNC(ring_al_destroy_display) { if ( RING_API_PARACOUNT != 1 ) { RING_API_ERROR(RING_API_MISS1PARA); return ; } if ( ! RING_API_ISPOINTER(1) ) { RING_API_ERROR(RING_API_BADPARATYPE); return ; } al_destroy_display((ALLEGRO_DISPLAY *) RING_API_GETCPOINTER(1,"ALLEGRO_DISPLAY")); } RING_FUNC(ring_al_get_new_display_flags) { if ( RING_API_PARACOUNT != 0 ) { RING_API_ERROR(RING_API_BADPARACOUNT); return ; } RING_API_RETNUMBER(al_get_new_display_flags()); } RING_FUNC(ring_al_set_new_display_flags) { if ( RING_API_PARACOUNT != 1 ) { RING_API_ERROR(RING_API_MISS1PARA); return ; } if ( ! RING_API_ISNUMBER(1) ) { RING_API_ERROR(RING_API_BADPARATYPE); return ; } al_set_new_display_flags( (int ) RING_API_GETNUMBER(1)); } RING_FUNC(ring_al_get_new_display_option) 84.3. Using the function prototype 929
Ring Documentation, Release 1.10 { if ( RING_API_PARACOUNT != 2 ) { RING_API_ERROR(RING_API_MISS2PARA); return ; } if ( ! RING_API_ISNUMBER(1) ) { RING_API_ERROR(RING_API_BADPARATYPE); return ; } if ( ! RING_API_ISSTRING(2) ) { RING_API_ERROR(RING_API_BADPARATYPE); return ; } RING_API_RETNUMBER(al_get_new_display_option( (int ) RING_API_GETNUMBER(1), RING_API_GETINTPOINTER(2))); RING_API_ACCEPTINTVALUE(2) ; } from the previous example we can see how much of time and effort is saved using the Code Generator. 84.4 Adding code to the generated code • To generate code directly type it between <code> and </code> Example : <code> /* some C code will be written here */ </code> We use this feature when we need to do something without the help of the code generator. for example including header files and defining constants using Macro. 84.5 Prefix for Functions Names • To determine a prefix in all of the functions names type it between <funcstart> and </funcstart> for ex- ample when we wrap the Allegro game programming library and we need all of the library functions to start with “al” we type the next code in the configuration file <funcstart> al </funcstart> 84.6 Generate function to wrap structures • To generate functions that wrap structures (create/delete/get structure members) just type the structures names between <struct> and </struct> also after the structure name you can type the structure members between { } separated by comma. Example 84.4. Adding code to the generated code 930
Ring Documentation, Release 1.10 <struct> ALLEGRO_COLOR ALLEGRO_EVENT { type , keyboard.keycode , mouse.x , mouse.y } </struct> from the previous example we will generate two function to create/delete the structure ALLEGRO_COLOR Also we will generate two functions to create/delete the structure ALLEGRO_EVENT and four functions to get the structure ALLEGRO_EVENT members (type, keyboard.keycode, mouse.x, mouse.y). 84.7 Determine Structure Members Types You can determine the pointer name before the strucuture member name. Example: SDL_Surface {flags,SDL_PixelFormat *format,w,h,pitch,void *pixels} 84.8 Defining Constants You can define constants using <constant> and </constant> The generator will generate the required functions to get the constant values And will define the constants to be used with the same name in Ring code using *.rh file that will be generated too. rh = Ring Header Example: <constant> MIX_DEFAULT_FORMAT SDL_QUIT SDL_BUTTON_LEFT SDL_BUTTON_MIDDLE SDL_BUTTON_RIGHT </constant> Note: You will need to pass the *.rh file name to parsec.ring after the generated source file name. Example: ring ..codegenparsec.ring libsdl.cf ring_libsdl.c ring_libsdl.rh 84.9 Register New Functions We can register functions by typing the function prototype between <register> and </register> We need this feature only when we don’t provide the function prototype as input directly where we need to write the code of this function. Example: <register> void al_exit(void) </register> 84.7. Determine Structure Members Types 931
Ring Documentation, Release 1.10 <code> RING_FUNC(ring_al_exit) { if ( RING_API_PARACOUNT != 0 ) { RING_API_ERROR(RING_API_BADPARACOUNT); return ; } exit(0); } </code> In the previous example we register the al_exit() function. This function is
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation
The Ring programming language - Version 1.10 documentation

The Ring programming language - Version 1.10 documentation

  • 2.
  • 3.
    CONTENTS 1 Applications developedin little hours 1 1.1 Quotes about Ring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.2 FetchStockData Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.3 Fifteen Puzzle Game 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 1.4 Google API Shortener Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.5 Analog Clock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.6 TicTacToe Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.7 Squares Puzzle Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 1.8 Video-Music-Player Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.9 Calculator Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 1.10 Windows StartUp Manager Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 1.11 Werdy Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 1.12 Samples in this book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 1.13 Innovative . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 1.14 Practical . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 2 Introduction 24 2.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 2.2 Ring and other languages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.3 Special Thanks to Matz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.4 History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 2.5 Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 2.6 License . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 3 Language Design 31 3.1 Why Ring? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 3.2 Designed for a Clear Goal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 3.3 Simple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 3.4 Trying to be natural . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 3.5 Encourage Organization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 3.6 Compact Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 3.7 Define Natural Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 3.8 Define Declarative Languages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 3.9 Syntax Flexibility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 3.10 Transparent Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 3.11 Visual Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 3.12 Smart Garbage Collector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 3.13 No Global Interpreter (VM) Lock - No GIL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 3.14 Fast Enough For Many Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 4 What is new in Ring 1.10? 41 i
  • 4.
    4.1 List ofchanges and new features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 4.2 Chess Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 4.3 Minesweeper Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 4.4 Knight Tour Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 4.5 Game of Life Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 4.6 Pong Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 4.7 Snakes And Ladder Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 4.8 More Games . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 4.9 Ring Extension for Visual Studio Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 4.10 The Ring Package Manager (RingPM) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 4.11 Better Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 4.12 More Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 5 What is new in Ring 1.9? 51 5.1 List of changes and new features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 5.2 New Game : Gold Magic 800 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 5.3 More Games . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 5.4 Better Ring Notepad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 5.5 Better StdLib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 5.6 BigNumber Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 5.7 RingPostgreSQL Extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 5.8 Deploying Web applications in the Cloud . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 5.9 Better RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 5.10 Better Memory Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 5.11 Better Code Generator for Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 5.12 More Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 6 What is new in Ring 1.8? 68 6.1 List of changes and new features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 6.2 Better Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 6.3 Find in files Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 6.4 String2Constant Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 6.5 StopWatch Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 6.6 More 3D Samples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 6.7 Compiling on Manjaro Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 6.8 Using This in the class region as Self . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 6.9 Default value for object attributes is NULL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 6.10 The For Loops uses the local scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 6.11 Merge binary characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 6.12 FoxRing Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 6.13 Better Form Designer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 6.14 Better Cards Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 6.15 Better RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 6.16 Better Code Generator For Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 6.17 Better Ring Compiler and VM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 6.18 Notes to extensions creators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 7 What is new in Ring 1.7? 81 7.1 List of changes and new features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 7.2 New Command: Load Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 7.3 ringvm_see() and ringvm_give() functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 7.4 ring_state_new() and ring_state_mainfile() functions . . . . . . . . . . . . . . . . . . . . . . . . . . 83 7.5 Better Trace Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 7.6 Better Ring Notepad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 ii
  • 5.
    7.7 Better RingQt. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 7.8 Better Ring2EXE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 7.9 Better RingZip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 7.10 Better Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 7.11 Better Ring VM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 7.12 RingLibuv Extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 8 What is new in Ring 1.6? 89 8.1 List of changes and new features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 8.2 Employee Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 8.3 New Tool: Ring2EXE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 8.4 Better Ring For Android . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 8.5 New Tool: Folder2qrc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 8.6 Better Scripts for building Ring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 8.7 RingConsoleColors Extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 8.8 RingMurmurHash Extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 8.9 Better Ring Notepad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 8.10 Better RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 8.11 Better StdLib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 8.12 Better RingVM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 8.13 Better RingREPL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 8.14 Using Tab instead of char(9) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 8.15 Using CR as Carriage return . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 8.16 Using the ! operator as not . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 8.17 Using && and || operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 8.18 Using ? to print expression then new line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 9 What is new in Ring 1.5? 100 9.1 List of changes and new features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 9.2 Video-Music-Player Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 9.3 Windows StartUp Manager Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 9.4 Calculator Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 9.5 Better Ring Notepad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 9.6 Better StdLib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 9.7 Better WebLib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 9.8 Better RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 9.9 Better Objects Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 9.10 RingFreeGLUT Extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 9.11 RingOpenGL Extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 9.12 Better Code Generator for Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 9.13 Better Documentation Generator for Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 9.14 Ring VM - Tracing Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 9.15 Trace Library and Interactive Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 9.16 More Syntax Flexibility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 9.17 Type Hints Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 9.18 Better Quality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 9.19 What is new in Ring 1.5.1? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 9.20 What is new in Ring 1.5.2? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 9.21 What is new in Ring 1.5.3? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 9.22 What is new in Ring 1.5.4? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142 10 What is new in Ring 1.4? 144 10.1 List of changes and new features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 10.2 Change: Basic Extensions are separated from RingVM . . . . . . . . . . . . . . . . . . . . . . . . . 144 iii
  • 6.
    10.3 The NaturalLibrary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 10.4 New Style is added to Ring Notepad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 10.5 RingREPL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 10.6 Convert between Numbers and Bytes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 10.7 Better StdLib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 10.8 Better WebLib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 10.9 Better RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 10.10 Qt Class Convertor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 10.11 What is new in Ring 1.4.1? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152 11 What is new in Ring 1.3? 156 11.1 List of changes and new features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 11.2 Better RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 11.3 Better Ring Notepad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160 11.4 Ring mode for Emacs Editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 11.5 Better StdLib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 11.6 Better Loop|Exit Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 11.7 New Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 11.8 Return Self by Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 11.9 Using ‘<’ and ‘:’ operators as ‘from’ keyword . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166 11.10 Embedding Ring in Ring without sharing the State . . . . . . . . . . . . . . . . . . . . . . . . . . . 166 11.11 RingZip Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 11.12 Form Designer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 12 What is new in Ring 1.2? 169 12.1 List of changes and new features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 12.2 New Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 12.3 Better Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170 12.4 Better Ring Notepad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170 12.5 Better RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 12.6 Objects Library for RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 12.7 RingLibCurl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172 12.8 Better Call Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 12.9 Using NULL instead of NULLPointer() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 12.10 Display Warnings Option . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 12.11 Better Quality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 13 What is new in Ring 1.1? 175 13.1 List of changes and new features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 13.2 Better Natural Language Programming Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 13.3 Generate/Execute Ring Object Files (*.ringo) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 13.4 Syntax Flexibility and different styles for I/O and Control Structures . . . . . . . . . . . . . . . . . . 176 13.5 New Functions and Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178 13.6 StdLib functions and classes written in Ring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 13.7 RingLibSDL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 13.8 Demo Project - Game Engine for 2D Games . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 13.9 RingSQLite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 13.10 Better Code Generator for Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183 13.11 Using Self.Attribute in the Class Region to define new attributes . . . . . . . . . . . . . . . . . . . . 183 13.12 Using This.Attribute in nested Braces inside the Class Methods . . . . . . . . . . . . . . . . . . . . 183 13.13 Better Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184 14 Building From Source Code 185 14.1 Building using Microsoft Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 14.2 Building using Ubuntu Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 iv
  • 7.
    14.3 Building usingFedora Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 14.4 Building using MacOS X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 14.5 Building using CMake . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 15 How to contribute? 195 15.1 Special thanks to contributors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 15.2 Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 15.3 Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 15.4 Samples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 15.5 Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 15.6 Editors Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 15.7 Libraries in Ring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 15.8 Extensions in C/C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 15.9 Compiler and Virtual Machine (VM) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 15.10 Ideas and suggestions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 16 Getting Started - First Style 197 16.1 Hello World . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 16.2 Run the program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 16.3 Create Executable File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 16.4 Not Case-Sensitive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 16.5 Multi-Line literals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 16.6 Getting Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 16.7 No Explicit End For Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 16.8 Using ? to print expression then new line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 16.9 Writing Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199 17 Getting Started - Second Style 200 17.1 Hello World . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 17.2 Run the program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 17.3 Create Executable File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 17.4 Not Case-Sensitive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 17.5 Multi-Line literals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 17.6 Getting Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 17.7 No Explicit End For Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 17.8 Writing Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 18 Getting Started - Third Style 202 18.1 Hello World . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 18.2 Run the program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 18.3 Create Executable File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 18.4 Not Case-Sensitive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 18.5 Multi-Line literals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 18.6 Getting Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 18.7 No Explicit End For Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 18.8 Writing Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 19 Using Ring Notepad 205 19.1 Ring Notepad - Main Window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 19.2 Creating and running your first Console Application . . . . . . . . . . . . . . . . . . . . . . . . . . 206 19.3 Creating and running your first GUI/Mobile Application . . . . . . . . . . . . . . . . . . . . . . . . 208 19.4 Creating and running your first Web Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209 19.5 Creating and running your first Desktop/Mobile Game . . . . . . . . . . . . . . . . . . . . . . . . . 210 19.6 The Main File in the Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211 19.7 The File Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212 v
  • 8.
    19.8 The EditMenu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 19.9 The View Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 19.10 The Program Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215 19.11 The Browser Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215 19.12 The Tools Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 19.13 The Distribute Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 19.14 The Help Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 20 Using Other Code Editors 218 20.1 Using Notepad++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 20.2 Using Geany . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219 20.3 Using Atom . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220 20.4 Using Sublime Text 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 20.5 Using Visual Studio IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222 20.6 Using Emacs Editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223 20.7 Visual Studio Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223 21 Variables 225 21.1 Dynamic Typing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 21.2 Deep Copy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 21.3 Weakly Typed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226 22 Operators 227 22.1 Arithmetic Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 22.2 Relational Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 22.3 Logical Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 22.4 Bitwise Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228 22.5 Assignment Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228 22.6 Misc Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228 22.7 Operators Precedence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229 23 Control Structures - First Style 230 23.1 Branching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230 23.2 Looping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231 23.3 Using The Step option with For in . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232 23.4 Using For in to modify lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 23.5 Do Again Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 23.6 Exit Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 23.7 Exit from two loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234 23.8 Loop Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234 23.9 Exit/Loop inside sub functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234 23.10 Short-circuit evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 23.11 Comments about evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 24 Control Structures - Second Style 237 24.1 Branching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 24.2 Looping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238 24.3 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239 25 Control Structures - Third Style 240 25.1 Branching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240 25.2 Looping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 25.3 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 26 Getting Input 245 vi
  • 9.
    26.1 Give Command. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245 26.2 GetChar() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245 26.3 Input() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246 27 Functions - First Style 247 27.1 Define Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247 27.2 Call Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247 27.3 Declare parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248 27.4 Send Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248 27.5 Main Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248 27.6 Variables Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249 27.7 Return Value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249 27.8 Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250 28 Functions - Second Style 251 28.1 Define Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251 28.2 Call Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251 28.3 Declare parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252 28.4 Send Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252 28.5 Main Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252 28.6 Variables Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253 28.7 Return Value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253 28.8 Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254 29 Functions - Third Style 255 29.1 Define Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255 29.2 Call Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255 29.3 Declare parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256 29.4 Send Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256 29.5 Main Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257 29.6 Variables Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257 29.7 Return Value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257 29.8 Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258 30 Program Structure 259 30.1 Source Code File Sections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259 30.2 Using Many Source Code Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259 30.3 Load Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260 31 Lists 261 31.1 Create Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261 31.2 Add Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261 31.3 Get List Size . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262 31.4 Delete Item From List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262 31.5 Get List Item . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262 31.6 Set List Item . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263 31.7 Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263 31.8 Sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264 31.9 Reverse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264 31.10 Insert Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265 31.11 Nested Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265 31.12 Copy Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265 31.13 First-class lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266 31.14 Using Lists during definition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266 31.15 Passing Lists to Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266 vii
  • 10.
    31.16 Access ListItems by String Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267 31.17 Passing Parameters or Argumnents Using List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267 31.18 Passing Parameters or Argumnents Using List Array . . . . . . . . . . . . . . . . . . . . . . . . . . 268 31.19 Creating a Multi-Dimensional Array using List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268 31.20 Swap Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269 32 Strings 271 32.1 String Literals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271 32.2 Get String Length . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271 32.3 Convert Letters Case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271 32.4 Access String Letters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272 32.5 Left() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272 32.6 Right() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272 32.7 Trim() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273 32.8 Copy() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273 32.9 Lines() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273 32.10 Substr() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274 32.11 Find substring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274 32.12 Get substring from position to end . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274 32.13 Get Number of Characters From Position . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274 32.14 Transform Substring To Another Substring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274 32.15 strcmp() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275 32.16 str2list() and list2str() Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275 32.17 Merge binary characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276 33 Date and Time 278 33.1 Clock() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278 33.2 ClocksPerSecond() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278 33.3 Time() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278 33.4 Date() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279 33.5 TimeList() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279 33.6 AddDays() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280 33.7 DiffDays() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280 33.8 EpochTime() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281 34 Check Data Type and Conversion 282 34.1 Check Data Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282 34.2 IsString() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282 34.3 IsNumber() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282 34.4 IsList() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283 34.5 Type() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283 34.6 IsNULL() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283 34.7 Check Character . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284 34.8 IsAlNum() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284 34.9 IsAlpha() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284 34.10 IsCntrl() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 34.11 IsDigit() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 34.12 IsGraph() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 34.13 IsLower() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 34.14 IsPrint() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286 34.15 IsPunct() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286 34.16 IsSpace() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286 34.17 IsUpper() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286 34.18 IsXdigit() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287 viii
  • 11.
    34.19 Conversion .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287 34.20 Number() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287 34.21 String() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287 34.22 Ascii() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288 34.23 Char() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288 34.24 Hex() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288 34.25 Dec() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288 34.26 Str2hex() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289 34.27 Hex2str() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289 35 Mathematical Functions 290 35.1 List of functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290 35.2 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290 35.3 Random() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292 35.4 SRandom() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293 35.5 Unsigned() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293 35.6 Decimals() Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294 35.7 Using _ in numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294 35.8 Using f after numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295 36 Files 296 36.1 Read() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297 36.2 Write() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297 36.3 Dir() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297 36.4 Rename() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298 36.5 Remove() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298 36.6 Fopen() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298 36.7 Fclose() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299 36.8 Fflush() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299 36.9 Freopen() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299 36.10 Tempfile() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300 36.11 Tempname() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300 36.12 Fseek() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300 36.13 Ftell() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300 36.14 Rewind() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301 36.15 Fgetpos() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301 36.16 Fsetpos() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301 36.17 Clearerr() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301 36.18 Feof() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301 36.19 Ferror() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301 36.20 Perror() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 36.21 Fgetc() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 36.22 Fgets() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 36.23 Fputc() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 36.24 Fputs() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 36.25 Ungetc() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 36.26 Fread() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 36.27 Fwrite() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 36.28 Fexists() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 36.29 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 36.30 Numbers and Bytes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305 37 System Functions 306 37.1 System() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306 ix
  • 12.
    37.2 SysGet() Function. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 37.3 IsMSDOS() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 37.4 IsWindows() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 37.5 IsWindows64() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 37.6 IsUnix() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 37.7 IsMacOSX() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308 37.8 IsLinux() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308 37.9 IsFreeBSD() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308 37.10 IsAndroid() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308 37.11 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308 37.12 Windowsnl() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309 37.13 Get Command Line Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309 37.14 Get Active Source File Name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310 37.15 PrevFileName() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310 37.16 CurrentDir() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311 37.17 ExeFileName() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311 37.18 ChDir() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311 37.19 ExeFolder() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311 37.20 Version() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311 37.21 Shutdown() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312 38 Eval() and Debugging 313 38.1 Try/Catch/Done . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313 38.2 Eval() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313 38.3 Raise() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314 38.4 Assert() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315 39 Demo Programs 316 39.1 Language Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316 39.2 Main Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317 40 ODBC Functions 320 40.1 odbc_init() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320 40.2 odbc_drivers() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321 40.3 odbc_datasources() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321 40.4 odbc_close() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321 40.5 Print List of ODBC Drivers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321 40.6 Print List of ODBC Data Sources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322 40.7 odbc_connect() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323 40.8 odbc_disconnect() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323 40.9 Open and Close Connection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323 40.10 odbc_execute() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323 40.11 odbc_colcount() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323 40.12 odbc_fetch() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324 40.13 odbc_getdata() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324 40.14 Execute Query and Print Result . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324 40.15 odbc_tables() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324 40.16 odbc_columns() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325 40.17 odbc_autocommit() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326 40.18 odbc_commit() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326 40.19 odbc_rollback() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326 40.20 Transactions and Using Commit and Rollback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326 40.21 Save and Restore images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327 41 MySQL Functions 329 x
  • 13.
    41.1 MySQL_Info() Function. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329 41.2 MySQL_Init() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 41.3 MySQL_Error() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 41.4 MySQL_Connect() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 41.5 MySQL_Close() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 41.6 MySQL_Query() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 41.7 Create Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331 41.8 Create Table and Insert Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331 41.9 MySQL_Insert_ID() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332 41.10 MySQL_Result() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333 41.11 MySQL_Next_Result() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333 41.12 Print Query Result . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333 41.13 MySQL_Columns() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333 41.14 MySQL_Result2() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334 41.15 MySQL_Escape_String() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335 41.16 Save Image inside the database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335 41.17 Restore Image From The Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336 41.18 MySQL_AutoCommit() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336 41.19 MySQL_Commit() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336 41.20 MySQL_Rollback() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336 41.21 Transaction Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336 42 SQLite Functions 338 42.1 sqlite_init() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338 42.2 sqlite_open() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338 42.3 sqlite_execute() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338 42.4 sqlite_close() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338 42.5 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339 43 PostgreSQL Functions 341 43.1 Loading the library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341 43.2 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341 43.3 RingPostgreSQL Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344 43.4 RingPostgreSQL Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345 44 Security and Internet Functions 348 44.1 MD5() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348 44.2 SHA1() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349 44.3 SHA256() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349 44.4 SHA512() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349 44.5 SHA384() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350 44.6 SHA224() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350 44.7 Encrypt() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350 44.8 Decrypt() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351 44.9 Encryption and Decryption Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351 44.10 File Hash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352 44.11 Randbytes() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352 44.12 Download() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352 44.13 SendEmail() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353 45 Object Oriented Programming (OOP) 354 45.1 Classes and Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354 45.2 Access Objects Using Braces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356 45.3 Composition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357 45.4 Setter and Getter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358 xi
  • 14.
    45.5 Private Attributesand Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358 45.6 Operator Overloading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359 45.7 Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362 45.8 Dynamic Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363 45.9 Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363 45.10 Printing Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364 45.11 Find() and List of Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364 45.12 Sort() and List of Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365 45.13 Using Self.Attribute and Self.Method() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367 45.14 Using This.Attribute and This.Method() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367 45.15 Using This in the class region as Self . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368 45.16 Default value for object attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369 46 Functional Programming 370 46.1 Pure Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370 46.2 First-class Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371 46.3 Higher-order Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371 46.4 Anonymous and Nested Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372 46.5 Equality of functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373 47 Reflection and Meta-programming 375 47.1 locals() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376 47.2 globals() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376 47.3 functions() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377 47.4 cfunctions() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377 47.5 islocal() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378 47.6 isglobal() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378 47.7 isfunction() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379 47.8 iscfunction() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379 47.9 packages() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379 47.10 ispackage() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 380 47.11 classes() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381 47.12 isclass() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381 47.13 packageclasses() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382 47.14 ispackageclass() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382 47.15 classname() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383 47.16 objectid() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383 47.17 isobject() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384 47.18 attributes() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384 47.19 methods() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384 47.20 isattribute() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385 47.21 isprivateattribute() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385 47.22 ismethod() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386 47.23 isprivatemethod() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386 47.24 addattribute() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387 47.25 addmethod() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387 47.26 getattribute() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389 47.27 setattribute() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390 47.28 mergemethods() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391 47.29 packagename() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392 48 Stdlib Functions 393 48.1 Puts() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393 48.2 Print() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393 xii
  • 15.
    48.3 Print2Str() Function. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394 48.4 GetString() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394 48.5 GetNumber() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394 48.6 AppPath() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394 48.7 JustFilePath() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394 48.8 JustFileName() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395 48.9 Value() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395 48.10 Times() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395 48.11 Map() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396 48.12 Filter() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396 48.13 Split() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396 48.14 SplitMany() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397 48.15 NewList() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397 48.16 Capitalized() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397 48.17 IsSpecial() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398 48.18 IsVowel() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398 48.19 LineCount() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398 48.20 Factorial() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398 48.21 Fibonacci() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399 48.22 IsPrime() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399 48.23 Sign() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399 48.24 List2File() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400 48.25 File2List() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400 48.26 StartsWith() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400 48.27 EndsWith() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400 48.28 GCD() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401 48.29 LCM() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401 48.30 SumList() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401 48.31 ProdList() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402 48.32 EvenOrOdd() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402 48.33 Factors() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402 48.34 IsPalindrome() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403 48.35 IsLeapYear() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403 48.36 BinaryDigits() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403 48.37 MatrixMulti() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404 48.38 MatrixTrans() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404 48.39 DayOfWeek() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404 48.40 Permutation() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405 48.41 ReadLine() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405 48.42 SubString() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405 48.43 ChangeString() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406 48.44 Sleep() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406 48.45 IsMainSourceFile() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406 48.46 DirExists() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407 48.47 MakeDir() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407 48.48 Fsize() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407 48.49 TrimAll() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407 48.50 TrimLeft() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408 48.51 TrimRight() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408 48.52 EpochTime() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408 48.53 SystemCmd() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408 48.54 ListAllFiles() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408 48.55 SystemSilent() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409 48.56 OSCreateOpenFolder() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409 xiii
  • 16.
    48.57 OSCopyFolder() Function. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409 48.58 OSDeleteFolder() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409 48.59 OSCopyFile() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 48.60 OSDeleteFile() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 48.61 OSRenameFile() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 48.62 List2Code() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 48.63 Str2ASCIIList() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 48.64 ASCIIList2Str() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411 49 Stdlib Classes 412 49.1 StdBase Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412 49.2 String Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413 49.3 List Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415 49.4 Stack Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417 49.5 Queue Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417 49.6 HashTable Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418 49.7 Tree Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419 49.8 Math Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420 49.9 DateTime Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424 49.10 File Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425 49.11 System Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426 49.12 Debug Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427 49.13 DataType Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 428 49.14 Conversion Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429 49.15 ODBC Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 430 49.16 MySQL Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431 49.17 SQLite Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 432 49.18 PostgreSQL Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433 49.19 Security Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435 49.20 Internet Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435 50 Declarative Programming using Nested Structures 436 50.1 Creating Objects inside Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436 50.2 Composition and Returning Objects and Lists by Reference . . . . . . . . . . . . . . . . . . . . . . 437 50.3 Executing code after the end of object access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439 50.4 Declarative Programming on the top of Object-Oriented . . . . . . . . . . . . . . . . . . . . . . . . 439 50.5 More beautiful Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440 51 Natural Language Programming 442 51.1 History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442 51.2 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442 51.3 Change the Ring Keyword ‘And’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443 51.4 Change the Ring Operator ‘+’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444 51.5 Change the ‘=’ operator to ‘is’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445 51.6 Using Eval() with our Natural Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446 51.7 BraceStart and BraceEnd Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 447 51.8 BraceExprEval Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448 51.9 Real Natural Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448 51.10 BraceError() Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449 51.11 Clean Natural Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450 52 Using the Natural Library 452 52.1 Natural Library - Demo Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452 52.2 Defining Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454 52.3 Natural Library - Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457 xiv
  • 17.
    52.4 Defining commandsusing classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457 53 Web Development (CGI Library) 459 53.1 Configure the Apache web server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459 53.2 Ring CGI Hello World Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460 53.3 Hello World Program using the Web Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460 53.4 Web Library Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461 53.5 HTTP Get Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461 53.6 HTTP POST Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466 53.7 Upload Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 468 53.8 Cookies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471 53.9 URL Encode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473 53.10 Templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474 53.11 HTML Special Characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476 53.12 Hash Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 477 53.13 Random Image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 479 53.14 HTML Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480 53.15 HTML Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 482 53.16 Gradient . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 483 53.17 Generating Pages using Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 484 53.18 HtmlPage Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 488 53.19 Using Bootstrap Library using Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 489 53.20 Using Bootstrap Library using Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490 53.21 CRUD Example using MVC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493 53.22 Users registration and Login . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 495 53.23 Database, ModelBase & ControllerBase classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 501 53.24 WebLib API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506 53.25 Application Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 508 53.26 Page Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 508 53.27 ScriptFunctions Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 510 53.28 StyleFunctions Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 511 53.29 WebPage Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 511 53.30 HtmlPage Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 512 54 Deploying Web Applications in the Cloud 513 54.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513 54.2 Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513 54.3 Ring source code files and permissions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 514 54.4 Hello World program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 515 54.5 Application Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 515 54.6 Deploying after updates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 515 54.7 Local Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516 55 Using RingLibCurl 517 55.1 Get Request . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517 55.2 Post Request . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517 55.3 Facebook Login . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517 55.4 Save Output to String . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 518 55.5 Get Stock Data From Yahoo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519 56 Using RingZip 521 56.1 Create Zip File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 521 56.2 Extract Zip File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 521 56.3 Print Files in Zip file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 521 56.4 Using RingZip Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 521 xv
  • 18.
    56.5 Zip ClassReference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 523 56.6 ZipEntry Class Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 523 57 Graphics and 2D Games programming using RingAllegro 524 57.1 Drawing, Animation and Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 524 57.2 Using TrueType Fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 531 57.3 Playing Sound Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 532 57.4 Scaling and Rotating Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 533 57.5 Display Transparent Image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534 57.6 Using Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 535 58 Using RingLibSDL 538 58.1 Create Window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 538 58.2 Display Image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 538 58.3 Switch between two images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539 58.4 Draw Rectangle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539 58.5 Display PNG Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540 58.6 Use TTF Fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540 58.7 Display Transparent Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540 58.8 Close Window Event . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 541 58.9 Mouse Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 542 58.10 Play Sound . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 543 59 Using RingLibuv 545 59.1 First Application using RingLibuv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 545 59.2 The Events Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546 59.3 Server Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546 59.4 Client Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 548 59.5 Server Example Using Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 549 59.6 Client Example Using Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 550 59.7 Threads Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 551 59.8 Threads Example - Using Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 552 60 Demo Project - Game Engine for 2D Games 553 60.1 Project Layers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 553 60.2 Graphics Library bindings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 553 60.3 Interface to graphics library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 554 60.4 Game Engine Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 554 60.5 Games Layer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 554 60.6 Game Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 555 60.7 GameObject Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 555 60.8 Sprite Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 556 60.9 Text Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 556 60.10 Animate Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557 60.11 Sound Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557 60.12 Map Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557 60.13 Using the Game Engine - Creating the Game Window . . . . . . . . . . . . . . . . . . . . . . . . . 558 60.14 Using the Game Engine - Drawing Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 558 60.15 Using the Game Engine - Moving Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 559 60.16 Using the Game Engine - Playing Sound . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561 60.17 Using the Game Engine - Animation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 562 60.18 Using the Game Engine - Animation and Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 563 60.19 Using the Game Engine - Sprite - Automatic Movement using Keyboard . . . . . . . . . . . . . . . 565 60.20 Using the Game Engine - Sprite - Keypress event . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566 60.21 Using the Game Engine - Sprite - Mouse event . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566 xvi
  • 19.
    60.22 Using theGame Engine - Sprite - State event . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567 60.23 Using the Game Engine - Animate - Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 568 60.24 Using the Game Engine - Map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 570 60.25 Using the Game Engine - Map Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 572 60.26 Using the Game Engine - Object and Drawing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 573 60.27 Stars Fighter Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 576 60.28 Flappy Bird 3000 Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 584 60.29 Super Man 2016 Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 591 61 Building Games For Android 603 61.1 Download Requirements and Update the Android SDK . . . . . . . . . . . . . . . . . . . . . . . . . 603 61.2 Project Folder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 603 61.3 Building the project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 604 62 Using RingOpenGL and RingFreeGLUT for 3D Graphics 606 62.1 Samples Source (Authors) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606 62.2 What is RingOpenGL? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606 62.3 What is RingFreeGLUT? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 607 62.4 The First Window using RingFreeGLUT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 607 62.5 Drawing using RingOpenGL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 608 62.6 The First Triangle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 610 62.7 Window Resize Event . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 611 62.8 Triangle Rotation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 612 62.9 Keyboard Events and Colors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 613 62.10 The Camera . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 616 62.11 Mouse Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 623 62.12 Menu Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 626 62.13 Using Fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 633 62.14 Frames Per Second . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 641 62.15 Make a Cube using RingOpenGL and RingFreeGLUT . . . . . . . . . . . . . . . . . . . . . . . . . 650 63 Using RingOpenGL and RingAllegro for 3D Graphics 654 63.1 3D Cube and Texture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 654 63.2 Many Cubes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 658 63.3 TicTacToe 3D Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 664 63.4 More 3D Samples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 673 64 The Gold Magic 800 Game 676 64.1 The Game Story . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 676 64.2 How to play? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 676 64.3 What will you learn? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 676 64.4 Screen Shots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 677 64.5 Source Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 678 65 Desktop and Mobile development using RingQt 680 65.1 The First GUI Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 680 65.2 The Events Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 682 65.3 Using Layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 682 65.4 Using the QTextEdit Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 683 65.5 Using the QListWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 684 65.6 Using QTreeView and QFileSystemModel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 687 65.7 Using QTreeWidget and QTreeWidgetItem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 688 65.8 Using QComboBox Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 690 65.9 Creating Menubar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691 65.10 Context Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 693 xvii
  • 20.
    65.11 Creating Toolbar. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 694 65.12 Creating StatusBar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 695 65.13 Using QDockWidget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 696 65.14 Using QTabWidget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 697 65.15 Using QTableWidget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 699 65.16 Using QProgressBar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 700 65.17 Using QSpinBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701 65.18 Using QSlider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 702 65.19 Using QDateEdit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 703 65.20 Using QDial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 704 65.21 Using QWebView . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 707 65.22 Using QCheckBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 708 65.23 Using QRadioButton and QButtonGroup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 709 65.24 Adding Hyperlink to QLabel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 711 65.25 QVideoWidget and QMediaPlayer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 712 65.26 Using QFrame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 714 65.27 Display Image using QLabel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 715 65.28 Menubar and StyleSheet Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 716 65.29 QLineEdit Events and QMessageBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 718 65.30 Other Widgets Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 720 65.31 Using the QTimer Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 722 65.32 Using QProgressBar and Timer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 723 65.33 Display Scaled Image using QLabel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 724 65.34 Using the QFileDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 725 65.35 Drawing using QPainter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 726 65.36 Printing using QPrinter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 728 65.37 Using QPrintPreviewDialog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 729 65.38 Creating More than one Window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 731 65.39 Playing Sound . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 732 65.40 Using the QColorDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 733 65.41 Using qLCDNumber Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 734 65.42 Movable Label Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 735 65.43 QMessagebox Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 736 65.44 Using QInputDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 737 65.45 Dialog Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 738 65.46 KeyPress and Mouse Move Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 739 65.47 Moving Objects using the Mouse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 740 65.48 Inheritance from GUI Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 744 65.49 Using QDesktopWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 745 65.50 Rotate Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 746 65.51 Change Focus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 748 65.52 Regular Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 749 65.53 Simple Client and Server Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 750 65.54 Dynamic Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 752 65.55 Weight History Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 753 65.56 Notepad Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 757 65.57 The Cards Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 772 65.58 Classes and their Methods to use the default events . . . . . . . . . . . . . . . . . . . . . . . . . . . 778 65.59 Methods to use Events with Events Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781 65.60 The Difference between Qt and RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 782 65.61 RingQt Classes and their Qt Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 783 65.62 New Classes names - Index Start from 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 783 65.63 Creating Reports using the WebLib and the GUILib . . . . . . . . . . . . . . . . . . . . . . . . . . 784 xviii
  • 21.
    66 Building RingQtApplications for Mobile 787 66.1 Download Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 787 66.2 Update the Android SDK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 787 66.3 Install Qt for Android . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 788 66.4 Using Ring2EXE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 788 66.5 The Qt project for your Ring application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 788 66.6 Comments about developing for Android using RingQt . . . . . . . . . . . . . . . . . . . . . . . . . 789 67 Objects Library for RingQt Application 791 67.1 Library Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791 67.2 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791 67.3 Open_WindowAndLink() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 794 67.4 Open_WindowInPackages() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 795 67.5 Objects Library Source Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 795 68 Using the Form Designer 796 68.1 The Designer Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 797 68.2 The Toolbox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 797 68.3 The Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 797 68.4 Running Forms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 798 68.5 Events Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 798 68.6 Keyboard Shortcuts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 801 68.7 Menubar Designer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 801 68.8 Window Flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 802 68.9 Entering Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 803 68.10 Using Layouts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 803 68.11 More Samples and Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 803 69 Multi-language Applications 804 69.1 Using String2Constant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 804 69.2 Form Designer Translation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 805 69.3 Forms Translation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 806 70 Scope Rules for Variables and Attributes 808 70.1 Three Scopes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 808 70.2 Defining Variables and Variables Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 808 70.3 How Ring find the variable? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 809 70.4 Using Object.Attribute . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 809 70.5 The Self Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 809 70.6 How Ring Define Variables and Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 810 70.7 Conflict between Global Variables and Class Attributes . . . . . . . . . . . . . . . . . . . . . . . . . 810 70.8 Conflict between Class Attributes and Local Variables . . . . . . . . . . . . . . . . . . . . . . . . . 811 70.9 Using Braces to access objects inside Class Methods . . . . . . . . . . . . . . . . . . . . . . . . . . 812 70.10 Accessing the class attributes from braces inside class methods . . . . . . . . . . . . . . . . . . . . 815 70.11 Creating a Class for each Window in GUI applications . . . . . . . . . . . . . . . . . . . . . . . . . 816 70.12 Conflict between self inside braces and self in the class region . . . . . . . . . . . . . . . . . . . . . 817 70.13 Using braces to escape from the current object scope . . . . . . . . . . . . . . . . . . . . . . . . . . 820 70.14 The For Loops uses the local scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 821 70.15 Summary of Scope Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 821 71 Scope Rules for Functions and Methods 824 71.1 How Ring find the Functions and Methods? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 824 71.2 Example about Sharing Names between Functions and Methods . . . . . . . . . . . . . . . . . . . . 825 71.3 Calling a function sharing the name with a method in the current class . . . . . . . . . . . . . . . . . 826 xix
  • 22.
    72 Syntax Flexibility828 72.1 Change Language Keywords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 828 72.2 Change Language Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 829 72.3 Load Syntax Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 830 72.4 Using “()” around the function parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 831 72.5 Using Semi-colon after and between statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 831 72.6 Using $ and @ in the start of the variable name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 832 72.7 Using the ‘elseif’ keyword as ‘but’ in if statement . . . . . . . . . . . . . . . . . . . . . . . . . . . 832 72.8 Using the ‘else’ keyword as ‘other’ in switch statement . . . . . . . . . . . . . . . . . . . . . . . . . 833 72.9 Using the ‘end’ keyword in different control structures . . . . . . . . . . . . . . . . . . . . . . . . . 833 72.10 Using braces to start and end different control structures . . . . . . . . . . . . . . . . . . . . . . . . 834 72.11 Using ‘put’ and ‘get’ as ‘see’ and ‘give’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 835 72.12 Using ‘case’ as ‘on’ in switch statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 835 72.13 Using ‘def’ as ‘func’ in functions/methods definition . . . . . . . . . . . . . . . . . . . . . . . . . . 836 72.14 Using braces { } in Packages/Classes/Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 836 72.15 Using ‘end’ keyword after Packages/Classes/Functions . . . . . . . . . . . . . . . . . . . . . . . . . 836 72.16 Using ‘endpackage’/’endclass’/’endfunc’ keywords after Packages/Classes/Functions . . . . . . . . 837 72.17 Ignore new lines after keywords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 837 73 Introduction to the Type Hints Library 838 73.1 Why Type Hints? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 838 73.2 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 838 73.3 User Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 838 73.4 Using Types inside Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 839 73.5 Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 839 74 Command Line Options 841 74.1 Printing Tokens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 841 74.2 Printing Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 843 74.3 Printing Intermediate Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 847 74.4 Printing Final Intermediate Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 850 74.5 CGI Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 854 74.6 No Run . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 854 74.7 Printing Instruction Operation Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 854 74.8 Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 854 74.9 Generate Object File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 855 75 Performance Tips 856 75.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 856 75.2 Creating Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 858 75.3 Arithmetic Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 859 75.4 Using len() and For Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 859 75.5 Calling Functions and Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 860 76 Distributing Ring Applications 862 76.1 Distributing Applications for Microsoft Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . 862 76.2 Protecting the Source Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 862 76.3 The files ring.ring and ring.ringo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 863 76.4 Creating Windows Installer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 863 76.5 Using C/C++ Compiler and Linker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 863 76.6 Distributing Applications and Games for Mobile . . . . . . . . . . . . . . . . . . . . . . . . . . . . 863 77 Distributing Ring Applications using Ring2EXE 864 77.1 Using Ring2EXE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 864 77.2 How Ring2EXE works? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 864 xx
  • 23.
    77.3 Example .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 865 77.4 Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 865 77.5 Building standalone console application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 866 77.6 Distributing RingAllegro Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 866 77.7 Distributing RingQt Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 867 77.8 Distributing Applications for Mobile using RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . 867 77.9 Building the Cards Game for Mobile using RingQt . . . . . . . . . . . . . . . . . . . . . . . . . . . 868 77.10 Building the Weight History Application for Mobile using RingQt . . . . . . . . . . . . . . . . . . . 868 77.11 Building the Form Designer for Mobile using RingQt . . . . . . . . . . . . . . . . . . . . . . . . . 869 77.12 Creating the Qt resource file using Folder2qrc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 871 77.13 Important Information about Ring2EXE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 871 78 The Ring Package Manager (RingPM) 873 78.1 Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 873 78.2 Discovering Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 873 78.3 Updating the RingPM Registry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 874 78.4 Installing Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 874 78.5 Printing List of Installed Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 875 78.6 Run Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 875 78.7 Update Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 876 78.8 Remove Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 876 78.9 Deleting All Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 876 78.10 Creating New Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 876 78.11 The Package Description File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 878 78.12 Create Package in the Current Folder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 879 78.13 The RingPM Registry File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 881 79 Low Level Functions 883 79.1 callgc() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 884 79.2 varptr() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 884 79.3 space() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 885 79.4 nullpointer() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 885 79.5 object2pointer() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 885 79.6 pointer2object() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 886 79.7 ispointer() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 886 79.8 ptrcmp() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 887 79.9 ringvm_cfunctionslist() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 887 79.10 ringvm_functionslist() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 887 79.11 ringvm_classeslist() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 888 79.12 ringvm_packageslist() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 889 79.13 ringvm_memorylist() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 890 79.14 ringvm_calllist() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 892 79.15 ringvm_fileslist() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 892 79.16 ringvm_settrace() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 893 79.17 ringvm_tracedata() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 893 79.18 ringvm_traceevent() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 894 79.19 ringvm_tracefunc() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 894 79.20 ringvm_scopescount() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 894 79.21 ringvm_evalinscope() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 895 79.22 ringvm_passerror() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 895 79.23 ringvm_hideerrormsg() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 895 79.24 ringvm_callfunc() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 895 79.25 Example - Using the Trace Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 895 79.26 Example - The Trace Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 899 xxi
  • 24.
    79.27 ringvm_see() function. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 903 79.28 ringvm_give() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 903 79.29 ringvm_info() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 903 80 The Trace Library and the Interactive Debugger 905 80.1 Loading the Trace library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 905 80.2 Trace All Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 905 80.3 Trace control flow between functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 905 80.4 Pass Error . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 906 80.5 Interactive Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 906 80.6 Execute Program Line by Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 906 80.7 BreakPoint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 907 80.8 Disable BreakPoints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 907 80.9 Using the Interactive Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 907 81 Embedding Ring in Ring 910 81.1 Embedding Ring in Ring without sharing the State . . . . . . . . . . . . . . . . . . . . . . . . . . . 910 81.2 Serial Execution of Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 911 81.3 ring_state_setvar() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 911 81.4 ring_state_new() and ring_state_mainfile() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 912 81.5 Runtime Errors when Embedding Ring in Ring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 913 82 Extension using the C/C++ languages 914 82.1 ring_ext.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 914 82.2 ring_ext.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 914 82.3 Module Organization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 915 82.4 Function Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 916 82.5 Check Parameters Count . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 916 82.6 Display Error Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 917 82.7 Check Parameters Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 917 82.8 Get Parameters Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 917 82.9 Return Value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 918 82.10 Function Prototype . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 918 82.11 Sin() Function Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 918 82.12 Fopen() and Fclose() Functions Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 918 82.13 Ring API - List Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 919 82.14 Ring API - String Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 921 82.15 MySQL_Columns() Function Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 921 82.16 Dynamic/Shared Libraries (DLL/So/Dylib) and LoadLib() function . . . . . . . . . . . . . . . . . . 922 82.17 Using RING_API_RETMANAGEDCPOINTER() . . . . . . . . . . . . . . . . . . . . . . . . . . . 923 83 Embedding Ring Language in C/C++ Programs 925 83.1 Ring State . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 925 83.2 Ring State Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 925 83.3 Ring State Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 926 84 Code Generator for wrapping C/C++ Libraries 928 84.1 Using the tool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 928 84.2 Configuration file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 928 84.3 Using the function prototype . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 928 84.4 Adding code to the generated code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 930 84.5 Prefix for Functions Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 930 84.6 Generate function to wrap structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 930 84.7 Determine Structure Members Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 931 84.8 Defining Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 931 xxii
  • 25.
    84.9 Register NewFunctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 931 84.10 Writing comments in the configuration file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 932 84.11 Executing code during code generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 932 84.12 Enum and Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 932 84.13 Filtering using Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 933 84.14 Constants Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 933 84.15 Configuration file for the Allegro Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 933 84.16 Threads Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 935 84.17 Code Generator Rules for Wrapping C++ Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 936 84.18 Using configuration file that wrap C++ Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 937 84.19 Configuration file for the Qt Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 937 84.20 Static Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 947 84.21 Loading Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 947 84.22 Managed Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 947 84.23 Configuration Files Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 948 85 Create your first extension 949 85.1 Location . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 949 85.2 Steps to create the extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 949 85.3 Testing the extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 950 86 Frequently Asked Questions (FAQ) 951 86.1 Why do we need Yet Another Programming Language (YAPL)? . . . . . . . . . . . . . . . . . . . . 951 86.2 Why is Ring weakly typed? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 952 86.3 What are the advantages to using Ring over Lisp or Smalltalk? . . . . . . . . . . . . . . . . . . . . . 952 86.4 Why is Ring largely focussed on UI creation? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 953 86.5 Is Ring some sort of an improvement of PHP? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 953 86.6 What are the advantages of using Ring over native C or C++? . . . . . . . . . . . . . . . . . . . . . 953 86.7 What is the difference between Ring and Python? And is Ring Open Source? . . . . . . . . . . . . . 953 86.8 What are the advantages to using Ring over Perl, PHP, Python or Ruby? . . . . . . . . . . . . . . . . 954 86.9 What are the advantages to using Ring over Tcl or Lua? . . . . . . . . . . . . . . . . . . . . . . . . 955 86.10 What are the advantages to using Ring over C# or Java? . . . . . . . . . . . . . . . . . . . . . . . . 955 86.11 The documentation says functional programming is supported, but then this happens? . . . . . . . . 955 86.12 Why the ability to define your own languages Instead of just handing over the syntax so you can parse it using whatever code you like? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 956 86.13 Why you can specify the number of loops you want to break out of? . . . . . . . . . . . . . . . . . . 956 86.14 Why Ring uses ‘See’, ‘Give’, ‘But’ and ‘Ok’ Keywords? . . . . . . . . . . . . . . . . . . . . . . . . 956 86.15 What is the philosophy behind data types in Ring? . . . . . . . . . . . . . . . . . . . . . . . . . . . 957 86.16 What about the Boolean values in Ring? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 957 86.17 What is the goal of including the “Main” function in Ring? . . . . . . . . . . . . . . . . . . . . . . . 958 86.18 Why the list index start from 1 in Ring? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 959 86.19 Why Ring is not case-sensitive? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 959 86.20 Why the Assignment operator uses Deep Copy? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 960 86.21 Is there constructor methods in Ring? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 961 86.22 What happens when we create a new object? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 961 86.23 Can we use the attributes by accessing the Getter and Setter methods? . . . . . . . . . . . . . . . . . 962 86.24 Why should a search of global names be made while defining the class attributes? . . . . . . . . . . 963 86.25 Why Ring doesn’t avoid the conflict between Global Variables and Class Attributes Names? . . . . . 964 86.26 Where can I write a program and execute it? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 965 86.27 How to get the file size using ftell() and fseek() functions? . . . . . . . . . . . . . . . . . . . . . . . 965 86.28 How to get the current source file path? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 965 86.29 What about predefined parameters or optional parameters in functions? . . . . . . . . . . . . . . . . 965 86.30 How to print keys or values only in List/Dictionary? . . . . . . . . . . . . . . . . . . . . . . . . . . 966 86.31 Why I get a strange result when printing nl with lists? . . . . . . . . . . . . . . . . . . . . . . . . . 966 xxiii
  • 26.
    86.32 Could youexplain the output of the StrCmp() function? . . . . . . . . . . . . . . . . . . . . . . . . 967 86.33 How to use many source code files in the project? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 967 86.34 Why this example use the GetChar() twice? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 968 86.35 How to use NULL and ISNULL() function? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 969 86.36 How to print lists that contains objects? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 970 86.37 How to insert an item to the first position in the list? . . . . . . . . . . . . . . . . . . . . . . . . . . 971 86.38 How to print new lines and other characters? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 971 86.39 Why we don’t use () after the qApp class name? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 971 86.40 Why the window title bar is going outside the screen? . . . . . . . . . . . . . . . . . . . . . . . . . 972 86.41 How to create an array of buttons in GUI applications? . . . . . . . . . . . . . . . . . . . . . . . . . 972 86.42 How to Close a window then displaying another one? . . . . . . . . . . . . . . . . . . . . . . . . . . 973 86.43 How to create a Modal Window? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 973 86.44 How can I disable maximize button and resize window? . . . . . . . . . . . . . . . . . . . . . . . . 974 86.45 How to use SQLite using ODBC? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 975 86.46 Can I connect to dbase/harbour database? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 976 86.47 Why setClickEvent() doesn’t see the object methods directly? . . . . . . . . . . . . . . . . . . . . . 977 86.48 Why I get Calling Function without definition Error? . . . . . . . . . . . . . . . . . . . . . . . . . . 977 86.49 Can Ring work on Windows XP? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 978 86.50 How to extend RingQt and add more classes? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 978 86.51 How to add Combobox and other elements to the cells of a QTableWidget? . . . . . . . . . . . . . . 981 86.52 How to perform some manipulations on selected cells in QTableWidget? . . . . . . . . . . . . . . . 981 86.53 Which of 3 coding styles are commonly used or recommended by the community? . . . . . . . . . . 982 87 General Information 983 87.1 Ring Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 983 87.2 Memory Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 983 87.3 Data Representation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 984 88 Language Reference 987 88.1 Language Keywords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 987 88.2 Language Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 989 88.3 Compiler Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 990 88.4 Runtime Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 990 88.5 Environment Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 992 88.6 Language Grammar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 992 88.7 Virtual Machine (VM) Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 993 89 RingQt Classes Reference 1000 89.1 CodeEditor Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1000 89.2 QAbstractButton Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1000 89.3 QAbstractItemView Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1001 89.4 QAbstractPrintDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1003 89.5 QAbstractScrollArea Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1003 89.6 QAbstractSlider Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1004 89.7 QAbstractSocket Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1005 89.8 QAbstractSpinBox Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1006 89.9 QAction Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1007 89.10 QAllEvents Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1009 89.11 QApp Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1013 89.12 QAxBase Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1013 89.13 QAxObject Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1015 89.14 QAxWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1015 89.15 QBitmap Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1015 89.16 QBluetoothAddress Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1015 xxiv
  • 27.
    89.17 QBluetoothDeviceDiscoveryAgent Class. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1016 89.18 QBluetoothDeviceInfo Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1016 89.19 QBluetoothHostInfo Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1017 89.20 QBluetoothLocalDevice Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1017 89.21 QBluetoothServer Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1018 89.22 QBluetoothServiceDiscoveryAgent Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1018 89.23 QBluetoothServiceInfo Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1019 89.24 QBluetoothSocket Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1020 89.25 QBluetoothTransferManager Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1021 89.26 QBluetoothTransferReply Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1021 89.27 QBluetoothTransferRequest Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1021 89.28 QBluetoothUuid Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1022 89.29 QBoxLayout Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1022 89.30 QBrush Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1023 89.31 QBuffer Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1023 89.32 QButtonGroup Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1023 89.33 QByteArray Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1024 89.34 QCalendarWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1026 89.35 QCamera Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1027 89.36 QCameraImageCapture Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1028 89.37 QCameraViewfinder Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1029 89.38 QChar Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1029 89.39 QCheckBox Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1031 89.40 QChildEvent Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1032 89.41 QClipboard Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1032 89.42 QColor Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1032 89.43 QColorDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1035 89.44 QComboBox Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1035 89.45 QCompleter Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1037 89.46 QCompleter2 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1038 89.47 QCompleter3 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1038 89.48 QCoreApplication Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1038 89.49 QCursor Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1040 89.50 QDate Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1040 89.51 QDateEdit Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1041 89.52 QDateTime Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1041 89.53 QDateTimeEdit Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1042 89.54 QDesktopServices Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1043 89.55 QDesktopWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1044 89.56 QDial Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1044 89.57 QDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1045 89.58 QDir Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1045 89.59 QDirModel Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1047 89.60 QDockWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1048 89.61 QDrag Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1049 89.62 QDragEnterEvent Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1049 89.63 QDragLeaveEvent Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1049 89.64 QDragMoveEvent Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1050 89.65 QDropEvent Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1050 89.66 QEvent Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1050 89.67 QFile Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1051 89.68 QFile2 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1051 89.69 QFileDevice Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1052 89.70 QFileDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1052 xxv
  • 28.
    89.71 QFileInfo Class. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1053 89.72 QFileSystemModel Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1055 89.73 QFont Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1056 89.74 QFontDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1058 89.75 QFontMetrics Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1058 89.76 QFrame Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1059 89.77 QFrame2 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1060 89.78 QFrame3 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1060 89.79 QGeoAddress Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1060 89.80 QGeoAreaMonitorInfo Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1061 89.81 QGeoAreaMonitorSource Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1061 89.82 QGeoCircle Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1061 89.83 QGeoCoordinate Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1062 89.84 QGeoPositionInfo Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1062 89.85 QGeoPositionInfoSource Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1063 89.86 QGeoRectangle Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1063 89.87 QGeoSatelliteInfo Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1064 89.88 QGeoSatelliteInfoSource Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1064 89.89 QGeoShape Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1064 89.90 QGradient Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1065 89.91 QGraphicsVideoItem Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1065 89.92 QGridLayout Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1065 89.93 QGuiApplication Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1066 89.94 QHBoxLayout Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1068 89.95 QHeaderView Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1068 89.96 QHostAddress Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1071 89.97 QHostInfo Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1071 89.98 QIODevice Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1072 89.99 QIcon Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1073 89.100QImage Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1073 89.101QInputDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1074 89.102QJsonArray Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1076 89.103QJsonDocument Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1076 89.104QJsonObject Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1077 89.105QJsonParseError Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1077 89.106QJsonValue Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1078 89.107QKeySequence Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1078 89.108QLCDNumber Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1078 89.109QLabel Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1079 89.110QLayout Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1080 89.111QLineEdit Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1081 89.112QLinearGradient Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1083 89.113QListView Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1083 89.114QListWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1084 89.115QListWidgetItem Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1085 89.116QMainWindow Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1086 89.117QMatrix4x4 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1088 89.118QMdiArea Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1089 89.119QMdiSubWindow Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1090 89.120QMediaObject Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1091 89.121QMediaPlayer Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1091 89.122QMediaPlaylist Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1092 89.123QMenu Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1092 89.124QMenuBar Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1093 xxvi
  • 29.
    89.125QMessageBox Class .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1094 89.126QMimeData Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1095 89.127QMutex Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1096 89.128QMutexLocker Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1096 89.129QNetworkAccessManager Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1096 89.130QNetworkProxy Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1097 89.131QNetworkReply Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1098 89.132QNetworkRequest Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1098 89.133QNmeaPositionInfoSource Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1099 89.134QObject Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1099 89.135QOpenGLBuffer Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1100 89.136QOpenGLContext Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1100 89.137QOpenGLDebugLogger Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1101 89.138QOpenGLFramebufferObject Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1102 89.139QOpenGLFunctions Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1102 89.140QOpenGLFunctions_3_2_Core Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1107 89.141QOpenGLPaintDevice Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1114 89.142QOpenGLShader Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1115 89.143QOpenGLShaderProgram Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1115 89.144QOpenGLTexture Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1119 89.145QOpenGLTimerQuery Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1121 89.146QOpenGLVersionProfile Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1121 89.147QOpenGLVertexArrayObject Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1122 89.148QOpenGLWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1122 89.149QPageSetupDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1123 89.150QPaintDevice Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1123 89.151QPainter Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1123 89.152QPainter2 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1126 89.153QPainterPath Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1126 89.154QPen Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1127 89.155QPicture Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1128 89.156QPixmap Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1128 89.157QPixmap2 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1130 89.158QPlainTextEdit Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1130 89.159QPoint Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1132 89.160QPointF Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1133 89.161QPrintPreviewDialog Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1133 89.162QPrintPreviewWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1133 89.163QPrinter Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1134 89.164QPrinterInfo Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1136 89.165QProcess Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1136 89.166QProgressBar Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1137 89.167QPushButton Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1138 89.168QQmlError Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1138 89.169QQuaternion Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1139 89.170QQuickWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1139 89.171QRadioButton Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1140 89.172QRect Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1140 89.173QRegion Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1142 89.174QRegularExpression Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1143 89.175QRegularExpressionMatch Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1143 89.176QRegularExpressionMatchIterator Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1144 89.177QScreen Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1144 89.178QScrollArea Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1145 xxvii
  • 30.
    89.179QScrollBar Class .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1146 89.180QSerialPort Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1146 89.181QSerialPortInfo Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1147 89.182QSize Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1148 89.183QSlider Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1148 89.184QSpinBox Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1148 89.185QSplashScreen Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1149 89.186QSplitter Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1149 89.187QSqlDatabase Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1150 89.188QSqlDriver Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1151 89.189QSqlDriverCreatorBase Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1152 89.190QSqlError Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1152 89.191QSqlField Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1152 89.192QSqlIndex Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1153 89.193QSqlQuery Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1153 89.194QSqlRecord Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1154 89.195QStackedWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1155 89.196QStandardPaths Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1156 89.197QStatusBar Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1156 89.198QString2 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1156 89.199QStringList Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1157 89.200QStringRef Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1158 89.201QSurfaceFormat Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1160 89.202QSystemTrayIcon Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1161 89.203QTabBar Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1161 89.204QTabWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1163 89.205QTableView Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1164 89.206QTableWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1166 89.207QTableWidgetItem Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1168 89.208QTcpServer Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1169 89.209QTcpSocket Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1170 89.210QTest Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1170 89.211QTextBlock Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1170 89.212QTextBrowser Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1171 89.213QTextCharFormat Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1172 89.214QTextCodec Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1174 89.215QTextCursor Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1174 89.216QTextDocument Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1176 89.217QTextEdit Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1178 89.218QTextStream Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1180 89.219QTextStream2 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1182 89.220QTextStream3 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1182 89.221QTextStream4 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1182 89.222QTextStream5 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1182 89.223QThread Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1182 89.224QThreadPool Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1183 89.225QTime Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1184 89.226QTimer Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1184 89.227QToolBar Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1185 89.228QToolButton Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1186 89.229QTreeView Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1186 89.230QTreeWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1188 89.231QTreeWidgetItem Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1191 89.232QUrl Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1192 xxviii
  • 31.
    89.233QUuid Class .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1193 89.234QVBoxLayout Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1193 89.235QVariant Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1194 89.236QVariant2 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1195 89.237QVariant3 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1195 89.238QVariant4 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1195 89.239QVariant5 Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1195 89.240QVector2D Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1196 89.241QVector3D Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1196 89.242QVector4D Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1197 89.243QVideoWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1198 89.244QVideoWidgetControl Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1198 89.245QWebEngineView Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1198 89.246QWebView Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1200 89.247QWebView Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1200 89.248QWidget Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1201 89.249QWindow Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1206 89.250QXmlStreamAttribute Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1210 89.251QXmlStreamAttributes Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1210 89.252QXmlStreamEntityDeclaration Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1211 89.253QXmlStreamEntityResolver Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1211 89.254QXmlStreamNamespaceDeclaration Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1211 89.255QXmlStreamNotationDeclaration Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1211 89.256QXmlStreamReader Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1212 89.257QXmlStreamWriter Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1213 89.258RingCodeHighlighter Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1214 90 RingMurmurHash Functions Reference 1215 90.1 MurmurHash1 functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1215 90.2 MurmurHash2 functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1215 90.3 MurmurHash3 functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1215 90.4 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1216 91 FoxRing Functions Reference 1217 91.1 FoxRing functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1217 91.2 frAbs() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1218 91.3 frAsc() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1218 91.4 frAddBs() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1219 91.5 frAt() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1219 91.6 frAtC() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1220 91.7 frChr() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1220 91.8 frEmpty() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1220 91.9 frFile() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1221 91.10 frFileToStr() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1221 91.11 frStr() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1221 91.12 frSetIfEmpty() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1222 91.13 frSpace() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1223 91.14 frInList() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1223 91.15 frForcePath() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1223 91.16 frAllTrim() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1223 91.17 frLTrim() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1224 91.18 frJustDrive() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1224 91.19 frJustExt() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1224 91.20 frJustStem() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1224 xxix
  • 32.
    91.21 frRTrim() function. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1224 91.22 frJustPath() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1225 91.23 frForceExt() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1225 91.24 frALines() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1225 91.25 frJustFName() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1225 91.26 frPadL() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1225 91.27 frPadR() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1225 91.28 frProper() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1225 91.29 frReplicate() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1225 91.30 frLen() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1226 91.31 frStuff() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1226 91.32 frSubStr() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1226 91.33 frStrTran() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1226 91.34 frListToString() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1226 91.35 frInt() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1227 91.36 frStringToList() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1227 91.37 frIIf() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1227 91.38 frVal() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1227 91.39 frBetween() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1227 91.40 frSetSeparatorTo() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1228 91.41 frTransform() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1228 91.42 frVarType() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1228 91.43 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1229 92 BigNumber Library 1231 92.1 Loading the library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1231 92.2 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1231 92.3 BigNumber Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1232 92.4 BigNumber Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1233 92.5 Library Source Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1233 93 RingLibCurl Functions Reference 1234 94 RingLibZip Functions Reference 1243 95 RingConsoleColors Functions Reference 1244 96 RingAllegro Functions Reference 1246 97 RingLibSDL Functions Reference 1265 98 RingLibuv Functions Reference 1290 99 RingFreeGLUT Functions Reference 1299 100RingOpenGL (OpenGL 1.1) Functions Reference 1308 101RingOpenGL (OpenGL 1.2) Functions Reference 1333 102RingOpenGL (OpenGL 1.3) Functions Reference 1359 103RingOpenGL (OpenGL 1.4) Functions Reference 1388 104RingOpenGL (OpenGL 1.5) Functions Reference 1418 105RingOpenGL (OpenGL 2.0) Functions Reference 1449 xxx
  • 33.
    106RingOpenGL (OpenGL 2.1)Functions Reference 1483 107RingOpenGL (OpenGL 3.0) Functions Reference 1525 108RingOpenGL (OpenGL 3.1) Functions Reference 1570 109RingOpenGL (OpenGL 3.2) Functions Reference 1616 110RingOpenGL (OpenGL 3.3) Functions Reference 1663 111RingOpenGL (OpenGL 4.0) Functions Reference 1709 112RingOpenGL (OpenGL 4.1) Functions Reference 1756 113RingOpenGL (OpenGL 4.2) Functions Reference 1803 114RingOpenGL (OpenGL 4.3) Functions Reference 1850 115RingOpenGL (OpenGL 4.4) Functions Reference 1897 116RingOpenGL (OpenGL 4.5) Functions Reference 1944 117RingOpenGL (OpenGL 4.6) Functions Reference 1991 118Resources 2039 118.1 Ring Language Website . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2039 118.2 Ring Group . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2039 118.3 Source Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2039 118.4 Arabic Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2039 118.5 Contact the Authors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2040 Index 2041 xxxi
  • 34.
    CHAPTER ONE APPLICATIONS DEVELOPED INLITTLE 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. It’s just released in 2016.01.25! In little days 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 little 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.” , 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 1
  • 35.
    Ring Documentation, Release1.10 “Very interesting effort.” , Giannakakis Kostas (Greece) “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) “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 1.1. Quotes about Ring 2
  • 36.
    Ring Documentation, Release1.10 “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) “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. Why bother with C/C++ when the syntax can be cryptic and they are largely antiquated - why should we still be dealing with header files, etc? Moreover, your comments on Java and C# being too verbose and forcing OOP onto the user is spot on as well - yet these languages are still primarily used by millions of programmers for the most mundane tasks. At this point, I’m led to believe that it’s simply a matter of legacy applications that still haven’t made the transition, as well as the ever-popular “Appeal to Popularity” fallacy shared by many in academia and enterprise. Then we come to languages, that are easier and much more modern, and yet even now, are being to show their age. Languages like Python which stresses whitespace and indentation, as well as (just like the formerly mentioned languages) irrelevant tokens for the conditional statements. Granted, it’s not as bad as tracking down various curly braces or semi-colons, but one misstep in indentation might as well be as frustrating to track down. The same could be true of Ruby, except with Ruby, we have even odder conventions embedded into the design of the language, which I don’t feel the need to address and moreover, we’re left with something like Lua which is missing a great many features that the previously mentioned languages include. There are many more languages and faults with them, we could claim that PHP is nothing more than a glue for web pages and backends but with so many frameworks available now, it’s falling by the wayside fast. Javascript is constantly being cloned. So, each of these general purpose languages, which we all know are mostly domain-specific and in some cases, also oriented at certain OS(C# was before 2016 and Obj-C/Swift will likely always be primarily for MacOS apps). So, then we’re left with several additional options, involving everything from hybrids to other imperative-based languages like D, GoLang, Scala, Julia, etc. But finally, there’s a new language called Ring - and yes, it may just end up ruling them all. It’s the unicorn we’ve finally been waiting to arrive, that can handle multiple domains, tasks, and paradigms. I honestly can’t wait to jump in and when I do I probably won’t come back up anytime soon. My only apprehension is that the language may not include a library or primitive functions for math as Python and Julia do. Aside from that, if so, hopefully, I won’t be having to use linear expressions as arrays (considering how intellectually lazy it is to do) and that there will be more support/tools as the community continues to grow. It’s crazy to think it’s only been around for a year and yet, it’s already, practically a batteries-included language.” 1.1. Quotes about Ring 3
  • 37.
    Ring Documentation, Release1.10 , 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) “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.” , Nuaua (Reddit) “The code that implements the Ring VM actually looks quite nice. There is a bunch of test code – great!” , Pe- terfirefly (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 i , Wim ten Brink (Quora - Top Writer (2018)) “Interesting alternative to Lua.” , djxtc (Sourceforge) 1.1. Quotes about Ring 4
  • 38.
    Ring Documentation, Release1.10 “Ring is a serious thing in the programming language landscape. One shoud 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 distruption, 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 todays 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 intutively. 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 assesing 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 1.2 FetchStockData Application URL : https://groups.google.com/forum/#!topic/ring-lang/-fa1U_SXSjo Author : Bert Mariani This App is written in Ring. It will fetch stock data from Yahoo and draw various types of charts. Any valid stock ticker can be entered, or selected from the drop down list - Select Symbol. It will not guarantee that you make money in the stock market. But it will visualize the history of the stock. 1.2. FetchStockData Application 5
  • 39.
    Ring Documentation, Release1.10 1.3 Fifteen Puzzle Game 2 URL : https://github.com/ring-lang/ring/blob/master/applications/fifteenpuzzle/CalmoSoftFifteenPuzzleGame.ring Author : Gal Zsolt (CalmoSoft) 1.3. Fifteen Puzzle Game 2 6
  • 40.
    Ring Documentation, Release1.10 1.3. Fifteen Puzzle Game 2 7
  • 41.
    Ring Documentation, Release1.10 1.4 Google API Shortener Application Author : John Storm (SienSystem) Hi everyone, Wanted to (finally) share a first release version of a small but very nice tool to shorten urls using the Google shortener API. The code is fully documented, maybe too documented, but, provides a good reference as to what is going on. You can obtain your own API key, or you can use my key to test and use the tool. Hope you enjoy the application. Please feel free to test at your convenience. Ring is FUN!! 1.4. Google API Shortener Application 8
  • 42.
    Ring Documentation, Release1.10 1.5 Analog Clock URL : https://github.com/ring-lang/ring/blob/master/applications/analogclock/AnalogClock-Image.ring Author : Bert Mariani 1.6 TicTacToe Game URL : https://github.com/AbdelrahmanGIT/RingSamples/blob/master/src/TecTacToe.ring Author : Abdelrahman Mohammed 1.5. Analog Clock 9
  • 43.
    Ring Documentation, Release1.10 1.7 Squares Puzzle Game URL : https://github.com/MajdiSobain/RingAllegro_SquaresPuzzle Author : Majdi Sobain This project is about (Squares Puzzle) popular game that I have programmed using ring language with its RingAllegro Library. The principle of this game is very known to all of us, which is moving squares to get the real full shape of the original picture. This game could be played using mouse and keyboard as well, showing a message of congratulations at the successful solving. 1.7. Squares Puzzle Game 10
  • 44.
    Ring Documentation, Release1.10 1.8 Video-Music-Player Application Author : Bert Mariani Screen Shot: 1.8. Video-Music-Player Application 11
  • 45.
    Ring Documentation, Release1.10 1.9 Calculator Application Author : Magdy Ragab Updated Version by Gal Zsolt and Bert Mariani Screen Shot: 1.9. Calculator Application 12
  • 46.
    Ring Documentation, Release1.10 1.10 Windows StartUp Manager Application URL : https://github.com/ring-lang/WinStartupManager Author : Majdi Sobain Windows Startup Manager is an application that has the ability to let the user control what programs should start at Windows booting time. It gives you the ability to show, edit, delete, or even add new programs entries to be lunched at Windows booting time. It is specialized at managing Windows startup entries that are stored in Windows Registry only, but provides a quick option to edit programs shortcuts type entries. Screen Shot: 1.10. Windows StartUp Manager Application 13
  • 47.
    Ring Documentation, Release1.10 1.11 Werdy Application URL : https://github.com/ring-lang/werdy Author : Magdy Ragab Quran application includes reading suras, searching and bookmarking. The applcation is provided for Windows, Linux and Android. 1.11. Werdy Application 14
  • 48.
    Ring Documentation, Release1.10 1.12 Samples in this book The next samples are developed in little hours and we will introduce them through this book. The next screen shot for he Ring Notepad application 1.12. Samples in this book 15
  • 49.
    Ring Documentation, Release1.10 The next screen shot for the Cards Game The next screen shot for the Cards Game (Android) 1.12. Samples in this book 16
  • 50.
    Ring Documentation, Release1.10 The next screen shot from the Web Development chapter 1.12. Samples in this book 17
  • 51.
    Ring Documentation, Release1.10 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.12. Samples in this book 18
  • 52.
    Ring Documentation, Release1.10 Super Man 2016 Game 1.12. Samples in this book 19
  • 53.
    Ring Documentation, Release1.10 The next screen shot for the TicTacToe 3D Game Screen Shot: 1.12. Samples in this book 20
  • 54.
    Ring Documentation, Release1.10 The next screen shot for the Gold Magic 800 Game 1.12. Samples in this book 21
  • 55.
    Ring Documentation, Release1.10 1.13 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.14 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/applications/formdesigner 1.13. Innovative 22
  • 56.
    Ring Documentation, Release1.10 We can run the Form Designer as Android application! 1.14. Practical 23
  • 57.
    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 create Console, GUI, Web, Games and Mobile applications. The language is designed to be Simple, Small, Flexible and Fast. Its Dynamic Language (Dynamic Typing and Weakly Typed) 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. Most of the PWCT source code was written in VFP and the software comes with a simple scripting language for creating the components called (RPWI). The software contains components that support code generation in pro- gramming languages like Harbour, C, Supernova & Python. 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 & can be used for developing different kinds of applications. Instead of using a mix of programming languages, I decided to use one programming language for creating the devel- opment environment, for components scripting & for creating the applications. I looked at many programming languages like C, C++, Java, C#, Lua, PHP, Python & Ruby. I avoided using C or C++ directly because I want high-level of productivity more than the level provided by these languages, also a language behind visual programming environment for novice programmers or professionals must be easy to use & productive. 24
  • 58.
    Ring Documentation, Release1.10 Java & C# are avoided for some reason too! I wanted to use a dynamic programming language and these languages are static typing, Java is multi-platform, also C# through Mono, but the use of huge number of classes and forcing the use of Object-Orientation, using a verbose language is not right for me. I need a small language, but fast and productive, also I need better control on the Garbage Collector (GC), I need a better one that is designed for fast applications. Lua is small and fast, but it’s avoided because I need more powerful language for large applications. PHP is a Web programming language and it’s syntax is very similar to C, this leads to a language not general as I want and not simple as I need to have. Python & Ruby are more like what I need, but I need something more simple, smaller, faster & productive. Python and Ruby are Case-Sensitive, the list index start counting from 0, you have to define the function before calling it, Ruby usage of Object-Orientation and message passing is more than what I need and decrease performance, Python syntax (indentation, using self, :, pass & _) is not good for my goals. All of these languages are successful languages, and very good for their domains, but what I need is a different language that comes with new ideas and intelligent implementation (Innovative, Ready, Simple, Small, Flexible and Fast). 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 Special Thanks to Matz Special Thanks to Matz (Yukihiro Matsumoto - The Creator of Ruby Programming Language) for spreading the word. 2.2. Ring and other languages 25
  • 59.
    Ring Documentation, Release1.10 2.4 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 2.4. History 26
  • 60.
    Ring Documentation, Release1.10 2.5 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) • Writen 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 • 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) • Use exit to go outside from loop in the Caller function (Use it for programming in the small only) 2.5. Features 27
  • 61.
    Ring Documentation, Release1.10 • 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 • List functions • File processing functions • Database support (ODBC, SQLite, MySQL & PostgreSQL) • Security Functions (OpenSSL) • Internet Functions (LibCurl) • Zip Functions 2.5. Features 28
  • 62.
    Ring Documentation, Release1.10 • 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 • 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) • Tracing and Debugging • Type Hints Library • Comes with Ring2EXE to distribute applications • RingLibuv 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. Features 29
  • 63.
    Ring Documentation, Release1.10 2.6 License The Ring Programming Language http://ring-lang.net/ Version 1.10 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.6. License 30
  • 64.
    CHAPTER THREE LANGUAGE DESIGN In thischapter we will learn about the basic concepts behind the language design. 3.1 Why Ring? The language is simple, trying to be natural, encourage organization and comes with transparent and visual implemen- tation. It comes with compact syntax and a group of features that enable the programmer to create natural interfaces and declarative domain-specific languages in a fraction of time. It is very small, fast and comes with smart garbage collector that puts the memory under the programmer control. It supports many programming paradigms, comes with useful and practical libraries. The language is designed for productivity and developing high quality solutions that can scale. 3.2 Designed for a Clear Goal • Applications programming language. • Productivity and developing high quality solutions that can scale. • Small and fast language that can be embedded in C/C++ projects. • Simple language that can be used in education and introducing Compiler/VM concepts. • General-Purpose language that can be used for creating domain-specific libraries, frameworks and tools. • Practical language designed for creating the next version of the Programming Without Coding Technology software. 3.3 Simple Ring is a very simple language, and has a very straightforward syntax. It encourages programmers to program without boilerplate code See "Hello, World!" The Main function is optional and will be executed after the statements, and is useful for using the local scope. Func Main See "Hello, World!" 31
  • 65.
    Ring Documentation, Release1.10 Uses Dynamic Typing and Lexical scoping. No $ is required before the variable name! You can use the ‘+’ operator for string concatenation and the language is weakly typed and will convert automatically between numbers and strings based on the context. nCount = 10 # Global variable Func Main nID = 1 # Local variable See "Count = " + nCount + nl + " ID = " + nID 3.4 Trying to be natural Ring is not case-sensitive See "Enter your name ? " Give name See "Hello " + Name # Name is the same as name The list index starts from 1 aList = ["one","two","three"] See aList[1] # print one Call functions before definition one() two() three() Func one See "One" + nl Func two See "two" + nl Func three See "three" + nl The assignment operator uses Deep copy (no references in this operation) aList = ["one","two","three"] aList2 = aList aList[1] = 1 see alist[1] # print 1 see aList2[1] # print one Pass numbers and strings by value, but pass lists and objects by reference. The for in loop can update the list items. Func Main aList = [1,2,3] update(aList) see aList # print one two three Func update aList for x in aList switch x on 1 x = "one" on 2 x = "two" on 3 x = "three" off next 3.4. Trying to be natural 32
  • 66.
    Ring Documentation, Release1.10 Using Lists during definition 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 Exit from more than one loop 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 3.5 Encourage Organization The language encourage organization, Forget bad days using languages where the programmer start with function then class then function and a strange mix between things! Each source file follow the next structure • Load Files • Statements and Global Variables • Functions • Packages and Classes This enable us to use Packages, Classes and Functions without the need to use a keyword to end these components. We can write one line comments and multi-line comments The comment starts with # or // Multi-line comments are written between /* and */ /* Program Name : My first program using Ring Date : 2015.05.08 */ See "What is your name? " # print message on screen give cName # get input from the user see "Hello " + cName # say hello! // See "Bye!" 3.6 Compact Syntax The language is not line sensitive, you don’t need to write ; after statements, also you don’t need to press ENTER or TAB, so we can write the next code See "The First Message" See " Another message in the same line! " + nl See "Enter your name?" Give Name See "Hello " + Name The next code create a class called Point contains three attributes X,Y and Z. No keywords is used to end the pack- age/class/function definition. Also, we can write the attributes names directly below the class name. 3.5. Encourage Organization 33
  • 67.
    Ring Documentation, Release1.10 Class Point X Y Z We can use classes and functions before their definition, In this example we will create new object, set the object attributes then print the object values. o1 = New point o1.x=10 o1.y=20 o1.z=30 See O1 Class Point X Y Z Instead of using the dot ‘.’ operator to access the object attributes and methods we can use braces { } to access the object, then we can use the object attributes and methods. o1 = New point { x=10 y=20 z=30 } See O1 Class Point X Y Z Now we will call a method after accessing the object using { } oPerson = new Person { Name = "Somebody" Address = "Somewhere" Phone = "0000000" Print() # here we call the Print() method } Class Person Name Address Phone Func Print See "Name :" + name + nl + "Address :" + Address + nl + "Phone : " + phone + nl When we use { } to access the object then write any attribute name, the language will check the class for any set- ter/getter methods that will be called automatically. New Number { See one # Execute GetOne() See two # Execute GetTwo() See three # Execute GetThree() } Class Number one two three Func GetOne See "Number : One" + nl return 1 Func GetTwo See "Number : Two" + nl return 2 Func GetThree See "Number : Three" + nl return 3 3.7 Define Natural Statements After the object access using { } if the class contains a method called BraceEnd() it will be executed! TimeForFun = new journey # The first surprise! TimeForFun { Hello it is me # What a beatiful programming world! } # Our Class Class journey 3.7. Define Natural Statements 34
  • 68.
    Ring Documentation, Release1.10 hello=0 it=0 is=0 me=0 func GetHello See "Hello" + nl func braceEnd See "Goodbye!" + nl We can execute code written in strings using the Eval() function cCode = "See 'Code that will be executed later!' " Eval(cCode) # execute the code to print the message We can create a list then execute code generated from that list aWords = ["hello","it","is","me"] for word in aWords cCode=word+"=0" eval(cCode) next We can read text files using the Read(cFileName) function and we can write files using the Write(cFileName,cString) function. See "Enter File Name:" Give cFileName See Read(cFileName) # Print the file content The next example presents how to create a class that defines two instructions The first instruction is : I want window The second instruction is : Window title = Expression 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 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++ 3.7. Define Natural Statements 35
  • 69.
    Ring Documentation, Release1.10 ok func settitle cValue if nWindowTitle = 1 nWindowTitle=0 see "Instruction : Window Title = " + cValue + nl ok To complete the previous example, use read() to get the content of a file that contains I want window The window title = "hello world" Then use eval() to execute the content of that file!. Also, you can update the methods GetWindow() and SetTitle() to create Real windows using the GUI Library 3.8 Define Declarative Languages We learned how to use Natural statements to execute our code and using the same features we can use nested structures to execute our code. The next example from the Web library, generate HTML document using the Bootstrap library. No HTML code is written directly in this example, we created a similar language (just as example) Then using this declarative language that uses nested structures, we generated the HTML Document.. The idea in this example is that the GetDiv() and GetH1() methods return an object that we can access using {} and after each object access the method BraceEnd() will be executed to send the generated HTML to the parent object until we reach to the root where BraceEnd() will print the output. 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 } } } 3.8. Define Declarative Languages 36
  • 70.
    Ring Documentation, Release1.10 The classes that power the declarative interface looks like this Class Link from ObjsBase title link Func braceend cOutput = nl+GetTabs() + "<a href='" + Link + "'> "+ Title + " </a> " + nl Class Div from ObjsBase Func braceend cOutput += nl+'<div' addattributes() AddStyle() getobjsdata() cOutput += nl+"</div>" + nl cOutput = TabMLString(cOutput) 3.9 Syntax Flexibility Ring comes with many styles for writing your source code! Also you can change the language keywords and operators and create your custom style! 3.10 Transparent Implementation Ring comes with transparent implementation. We can know what is happening in each compiler stage and what is going on during the run-time by the Virtual Machine Example : ring helloworld.ring -tokens -rules -ic See "Hello, World!" Output ================================================================== Tokens - Generated by the Scanner ================================================================== Keyword : SEE Literal : Hello, World! EndLine ================================================================== ================================================================== Grammar Rules Used by The Parser ================================================================== Rule : Program --> {Statement} Line 1 Rule : Factor --> Literal Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift 3.9. Syntax Flexibility 37
  • 71.
    Ring Documentation, Release1.10 Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> 'See' Expr ================================================================== ================================================================== Byte Code - Before Execution by the VM ================================================================== PC OPCode Data 1 FuncExE 2 PushC Hello, World! 3 Print 4 ReturnNull ================================================================== Hello, World! 3.11 Visual Implementation The Ring programming language is designed using the PWCT visual programming tool and you will find the visual source of the language in the folder “visualsrc” - *.ssf files and the generated source code (In the C Language) in the src folder and the include folder. The next screen shot from the ring_vm.ssf file (Generate ring_vm.c and ring_vm.h) 3.11. Visual Implementation 38
  • 72.
    Ring Documentation, Release1.10 The next screen shot from the ring_list.ssf file (Generate ring_list.c and ring_list.h) 3.12 Smart Garbage Collector Avoid memory problems :- • Invalid Memory Access • Memory leaks • Uninitialized Memory Access • Dangling pointer Rules :- • Global variables always stay in the memory, until you delete these variables using the assignment statement. • Local variables always deleted after the end of the function. • The programmer have full control on when to delete the variable from the memory using the Assignment state- ment. Example: aList = [1,2,3,4,5] aList = "nice" After the second line directly, The list [1,2,3,4,5] will be deleted from the memory and we will have a string “nice” • The programmer can call the function callgc() to force running the garbage collector. • If we have a reference to a variable (when we pass objects and lists to functions), then deleting variables will be based on reference counting, if no references everything will be deleted, but if we have a reference, the data will stay in memory. 3.12. Smart Garbage Collector 39
  • 73.
    Ring Documentation, Release1.10 3.13 No Global Interpreter (VM) Lock - No GIL When we use threads in Ring applications, We don’t have global interpreter (VM) lock (No GIL) So threads can work in parallel and execute Ring instructions at the same time This is better for threads and concurrency (More Faster!) 3.14 Fast Enough For Many Applications 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! 3.13. No Global Interpreter (VM) Lock - No GIL 40
  • 74.
    CHAPTER FOUR WHAT IS NEWIN RING 1.10? In this chapter we will learn about the changes and new features in Ring 1.10 release. 4.1 List of changes and new features Ring 1.10 comes with the next features! • Chess Game • Minesweeper Game • Knight Tour Game • Game of Life Game • Pong Game • Snakes and Ladder Game • More Games • Ring Extension for Visual Studio Code • The Ring Package Manager (RingPM) • Better Tests • More Improvements 4.2 Chess Game Chess Game (2 Players) 41
  • 75.
    Ring Documentation, Release1.10 4.3 Minesweeper Game The objective of the game is to clear a rectangular board containing hidden “mines” or bombs without detonating any of them. 4.3. Minesweeper Game 42
  • 76.
    Ring Documentation, Release1.10 4.4 Knight Tour Game Move to every square on the chess board, using only the moves of a knight. Can you visit every square in just 63 moves? 4.4. Knight Tour Game 43
  • 77.
    Ring Documentation, Release1.10 4.5 Game of Life Game The game is a zero-player game, meaning that its evolution is determined by its initial state, requiring no further input. One interacts with the Game of Life by creating an initial configuration and observing how it evolves, or, for advanced players, by creating patterns with particular properties. 4.5. Game of Life Game 44
  • 78.
    Ring Documentation, Release1.10 4.6 Pong Game Simple “tennis like” game features two paddles and a ball. The goal is to defeat your opponent once the opponent misses a ball. 4.6. Pong Game 45
  • 79.
    Ring Documentation, Release1.10 4.7 Snakes And Ladder Game The Snakes and Ladder Game using Ring Game Engine for 2D Games 4.7. Snakes And Ladder Game 46
  • 80.
    Ring Documentation, Release1.10 4.8 More Games The next games are added to the application folder • Lights Out Game • Dots and Boxes Game • Magic Four Game • Sum Puzzle Game The next screen shot for the Sum Puzzle Game 4.8. More Games 47
  • 81.
    Ring Documentation, Release1.10 4.9 Ring Extension for Visual Studio Code This extension support the Ring programming language in Visual Studio Code 4.9. Ring Extension for Visual Studio Code 48
  • 82.
    Ring Documentation, Release1.10 4.10 The Ring Package Manager (RingPM) Ring comes with a package manager (RingPM) that we can use to install, update and remove packages. 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 =========================================================================== 4.11 Better Tests New framework for Ring programming language tests that test the language. 4.10. The Ring Package Manager (RingPM) 49
  • 83.
    Ring Documentation, Release1.10 4.12 More Improvements 1. Ring Compiler : Better support for (Operator Operator) to avoid checking the first operator when it’s a literal. 2. Ring Compiler : When we load a file that doesn’t exist, display the caller file name in the error message. 3. Ring Compiler : Support source code files with one line of comment without end of line. 4. Ring Compiler : change nNoAssignment attribute in Parser Structure to nNewObject. 5. Ring VM : Better support for the (Return) command inside braces that access new objects. 6. Ring VM : Dir() Function - Don’t add ”.” and ”..” to the output 7. Ring VM : Dir() Function - Correct output for the item type (file|directory) on Linux and macOS. 8. Ring VM : ICO_LISTSTART - Clean pVM->aSetProperty when setting an object attribute. 9. Ring VM : ICO_NEWOBJECT - Clean pVM->aSetProperty when setting an object attribute. 10. Ring VM : Better code for Setter and Getter methods support. 11. Ring2EXE: The libraries information are stored in separated files in ring/ring2exe/libs folder. 12. WebLib : Separate the library to many source code files. 13. StdLib : IsVowel() function - Better Code. 14. RingQt : Count(), Left(), Mid() and Right() methods are added to QString class. 15. Better Read Me File 4.12. More Improvements 50
  • 84.
    CHAPTER FIVE WHAT IS NEWIN RING 1.9? In this chapter we will learn about the changes and new features in Ring 1.9 release. 5.1 List of changes and new features Ring 1.9 comes with the next features! • New Game : Gold Magic 800 • More Games • Better Ring Notepad • Better StdLib • BigNumber Library • RingPostgreSQL Extension • Deploying Web applications in the Cloud • Better RingQt • Better Memory Management • Better Code Generator for Extensions • More Improvements 5.2 New Game : Gold Magic 800 The Gold Magic 800 is a new puzzle game. Ring 1.9 comes with the Demo Version (18 Levels) and the game source code. Steam Page (44 Levels) : https://store.steampowered.com/app/939200/Gold_Magic_800/ We can select the level 51
  • 85.
    Ring Documentation, Release1.10 The next screen shot for level (1) The Gold Magic 800 Level Editor 5.2. New Game : Gold Magic 800 52
  • 86.
    Ring Documentation, Release1.10 5.3 More Games The next games are added to Ring Applications 1. The 2048 Game 2. The Memory Game 3. The Wise Quadrat Game 4. The Tessera Game 5. The Othello Game The next screen shot for the 2048 game on Android 5.3. More Games 53
  • 87.
    Ring Documentation, Release1.10 The next screen shot for the Tessera game 5.3. More Games 54
  • 88.
    Ring Documentation, Release1.10 The next screen shot for the Othello game 5.3. More Games 55
  • 89.
    Ring Documentation, Release1.10 5.4 Better Ring Notepad 1. New Style 2. New Mode 3. Tabs for opened files 4. Support executing batch files 5.4. Better Ring Notepad 56
  • 90.
    Ring Documentation, Release1.10 5.5 Better StdLib 1. The List2Code() function is added to the StdLib 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 ] 2. The Str2ASCIIList() and ASCIIList2Str() are added to the StdLib Using these functions we can convert between string of bytes and a list of numbers where each item represent the ASCII code of one byte in the string. So we may convert a string of bytes to ASCII List then do some operations on the list numbers (Like XOR) Example: load "stdlibcore.ring" cStr = "MmMm" aList = Str2ASCIILIST(cStr) ? aList 5.5. Better StdLib 57
  • 91.
    Ring Documentation, Release1.10 cStr2 = ASCIIList2Str(aList) ? cStr2 ? len(cStr2) Output: 77 109 77 109 MmMm 4 5.6 BigNumber Library Using the BigNumber library we can do arithmetic operations on huge numbers. Example: load "bignumber.ring" num1 = "62345678901234567891678345123456789" ### Big num2 = "1237894567890123419871236545" ### Small num3 = "64" ### Divide Small num4 = "765432" num5 = "3" ### Power ? "Add big numbers:" a1 = new BigNumber(num1) a1.Print() a2 = new BigNumber(num2) a2.Print() a3 = a1 + a2 a3.Print() ? nl ? "Substract big numbers:" a1 = new BigNumber(num1) a1.Print() a2 = new BigNumber(num2) a2.Print() a3 = a1 - a2 a3.Print() ? nl ? "Multiply big numbers:" a1 = new BigNumber(num1) a1.print() a2 = new BigNumber(num2) a2.print() a3 = a1 * a2 a3.print() ? nl ? "Divide big numbers:" a1 = new BigNumber(num1) a1.print() a2 = new BigNumber(num2) a2.print() a3 = a1 / a2 a3.print() ? nl ? "Divide big numbers: by very small number" a1 = new BigNumber(num1) a1.print() a2 = new BigNumber(num3) a2.print() a3 = a1 / a2 a3.print() ? nl ? "Power of big number:" a1 = new BigNumber(num1) a1.print() a2 = new BigNumber(num5) a2.print() 5.6. BigNumber Library 58
  • 92.
    Ring Documentation, Release1.10 a3 = a1 ^ a2 a3.print() ? nl Output: Add big numbers: 62345678901234567891678345123456789 1237894567890123419871236545 62345680139129135781801764994693334 Substract big numbers: 62345678901234567891678345123456789 1237894567890123419871236545 52345687663340000001554925252220244 Multiply big numbers: 62345678901234567891678345123456789 1237894567890123419871236545 77177377243260150103462178714197454736432472780119682305154005 Divide big numbers: 62345678901234567891678345123456789 1237894567890123419871236545 50364288 Divide big numbers: by very small number 62345678901234567891678345123456789 64 974151232831790123307474142554012 Power of big number: 62345678901234567891678345123456789 3 242336636261471172092347146031727004 (Output continue in next line) 371698195628343934238988256152289508 (Output continue in next line) 493964611043228971692389860897069 For more information check the BigNumber Library Chapter in the documentation 5.7 RingPostgreSQL Extension Ring 1.9 provide native support for PostgreSQL database using the RingPostgreSQL Extension. Example: load "postgresqllib.ring" conninfo = "user=postgres password=sa dbname = mahdb" exit_nicely = func conn { PQfinish(conn) shutdown(1) } 5.7. RingPostgreSQL Extension 59
  • 93.
    Ring Documentation, Release1.10 conn = PQconnectdb(conninfo) if (PQstatus(conn) != CONNECTION_OK) fputs(stderr, "Connection to database failed: "+PQerrorMessage(conn)) call exit_nicely(conn) ok 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) 5.7. RingPostgreSQL Extension 60
  • 94.
    Ring Documentation, Release1.10 ok nFields = PQnfields(res) for i = 1 to nFields ? 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 For more information check the PostgreSQL Chapter in the documentation 5.8 Deploying Web applications in the Cloud 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/ 5.8. Deploying Web applications in the Cloud 61
  • 95.
    Ring Documentation, Release1.10 For more information check the Deploying Web Applications In The Cloud chapter in the documentation. 5.9 Better RingQt 1. The next classes are added to RingQt • QDrag • QMimeData • QDropEvent • QDragMoveEvent • QDragEnterEvent • QDragLeaveEvent • QClipboard • QChildEvent • QGeoPositionInfo • QGeoCoordinate • QGeoAddress • QGeoAreaMonitorInfo • QGeoAreaMonitorSource • QGeoCircle • QGeoPositionInfoSource 5.9. Better RingQt 62
  • 96.
    Ring Documentation, Release1.10 • QGeoRectangle • QGeoShape • QGeoSatelliteInfo • QGeoSatelliteInfoSource • QNmeaPositionInfoSource • QAxWidget • QTextStream • QPrinterInfo • QPrintPreviewWidget • QPrintPreviewDialog • QPageSetupDialog • QAbstractPrintDialog • QPrintDialog 2. The next classes are updated • QAllEvents Class : New Events (ChildAdded, ChildPolished, ChildRemoved). • QPainter Class : Updated Methods (drawConvexPloygon, drawPoints, drawPolyline) Accept Ring list of points. • QVariant : More versions that accept different parameters when creating the object. • QAxBase : Different versions for the dynamicCall() and querySubObject() methods. The next example for using 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 printer1 { painter = new qpainter() { begin(printer1) myfont = new qfont("Times",50,-1,0) setfont(myfont) drawtext(100,100,"Test - Page (1)") printer1.newpage() 5.9. Better RingQt 63
  • 97.
    Ring Documentation, Release1.10 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: 5.9. Better RingQt 64
  • 98.
    Ring Documentation, Release1.10 5.10 Better Memory Management The Ring API is updated to include RING_API_RETMANAGEDCPOINTER() Using RING_API_RETMANAGEDCPOINTER() the Ring extensions written in C/C++ languages can return a man- aged pointer to Ring. This pointer can be controlled by the Ring VM using reference counting. 5.10. Better Memory Management 65
  • 99.
    Ring Documentation, Release1.10 This is important to avoid the need to write code that free the unmanaged resources like QPixMap objects in RingQt. Also the Code Generator for extensions is updated to automatically use RING_API_RETMANAGEDCPOINTER() based on need. Syntax: RING_API_RETMANAGEDCPOINTER(void *pValue,const char *cPointerType, void (* pFreeFunc)(void *,void *)) For more information about RING_API_RETMANAGEDCPOINTER() See the “Extension using the C/C++ languages” Chapter in the documentation 5.11 Better Code Generator for Extensions 1. The code generator for extensions is updated to support the <loadfile> command <loadfile> filename.cf This is useful to separate the extension configuraition file to many files Example: The file : qt_module_network.cf in the RingQt Extension <comment> Module (network) </comment> <loadfile> qabstractsocket.cf <loadfile> qnetworkproxy.cf <loadfile> qtcpsocket.cf <loadfile> qtcpserver.cf <loadfile> qhostaddress.cf <loadfile> qhostinfo.cf <loadfile> qnetworkrequest.cf <loadfile> qnetworkaccessmanager.cf <loadfile> qnetworkreply.cf 2. The code generator support the <managed> option when defining classes. Using this option, the generator will use RING_API_RETMANAGEDCPOINTER() to return the C pointer. So the Garabage Collector will manage these C pointers. Example <class> name: QFont para: QString, int, int, bool managed </class> 5.12 More Improvements 1. Ring Compiler - The Rule (Factor -> ‘-‘ Expr) changed to (Factor -> ‘-‘ Factor). 2. Ring VM - Better Error Message. 5.11. Better Code Generator for Extensions 66
  • 100.
    Ring Documentation, Release1.10 3. Better code for IsNULL() function - updated to check pointers too. 4. Better code for ringvm_evalinscope() function - used by the Trace Library. 5. Better code for Space() function. 6. Better code for Hex() and Dec() functions. 7. Better code for Download() function. 8. Better code for SubStr() function. 9. Better code for the Unsigned() function. 10. Better code for Chdir() function. 11. Better code for Tempname() function. 12. Better code for HashTable - New Key (using ring_strdup() instead of strdup() function). 13. New Function : SRandom() - Initialize random number generator. 14. New Function : IsPointer(). 15. IsList() will not return True for C Pointers, we have now the IsPointer() function. 16. The ? Operator is updated to respect the ringvm_see() function. 17. Scripts to run Ring tests on Linux and macOS (Not only Windows). 18. RingAllegro is Updated from Allegro 5.1 to Allegro 5.2. 19. Shader Functions are added to RingAllegro. 20. Joystick Functions are added to RingAllegro. 21. Network functions are added to RingLibSDL. 22. Game Engine for 2D Games - Text Class - Check the font object before usage. 23. Game Engine for 2D Games - Automatic support for Joystick. 24. RingLibCurl is updated to automatically use CURLOPT_COPYPOSTFIELDS when needed. 25. Ring Notepad - Find Previous Feature. 26. Ring Notepad - Default Style. 27. Ring Notepad - Support using Non-English language (Like Arabic) in file names. 28. Form Designer - Nice Aliginment for Toolbox Icons. 29. Form Desginer - QAllEvents Class - Mouse Double Click Event. 30. Find in Files - Replace and Replace All options. 31. Qt Class Converter is updated for better conversion results. 32. More samples are added to ring/samples/other folder. 33. Code Refactoring for Ring Notepad, RingQt, Game Engine for 2D Games. 34. Better Documentation - Many images are updated to reflect the current state of Ring Environment. 35. Better Documentation - More chapters are added to the documentation. 5.12. More Improvements 67
  • 101.
    CHAPTER SIX WHAT IS NEWIN RING 1.8? In this chapter we will learn about the changes and new features in Ring 1.8 release. 6.1 List of changes and new features Ring 1.8 comes with the next features! • Better Performance • Find in files Application • String2Constant Application • StopWatch Application • More 3D Samples • Compiling on Manjaro Linux • Using This in the class region as Self • Default value for object attributes is NULL • The For Loops uses the local scope • Merge binary characters • FoxRing Library • Better Form Designer • Better Cards Game • Better RingQt • Better Code Generator For Extensions • Better Ring Compiler and VM • Notes to extensions creators 6.2 Better Performance Ring 1.8 is faster than Ring 1.7 The performance gain is between 10% and 100% based on the application. Check the 3D samples in this release to get an idea about the current performance. 68
  • 102.
    Ring Documentation, Release1.10 For more information check the Performance Tips chapter. 6.3 Find in files Application Ring 1.8 comes with Find in files application 6.4 String2Constant Application Ring 1.8 comes with String2Constant application 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 the Arabic language. For more information check the Multi-language Applications chapter. 6.3. Find in files Application 69
  • 103.
    Ring Documentation, Release1.10 6.5 StopWatch Application Ring 1.8 comes with StopWatch application 6.5. StopWatch Application 70
  • 104.
    Ring Documentation, Release1.10 6.6 More 3D Samples Ring 1.8 comes with more 3D Samples The next screen shot for the Top-Down view - Many levels of cubes sample 6.6. More 3D Samples 71
  • 105.
    Ring Documentation, Release1.10 The next screen shot for the Camera Sample The next screen shot for the Camera and background sample Developer : Azzeddine Remmal 6.6. More 3D Samples 72
  • 106.
    Ring Documentation, Release1.10 6.7 Compiling on Manjaro Linux Ring 1.8 is tested on Manjaro Linux too Tests by : Iip Rifai 6.7. Compiling on Manjaro Linux 73
  • 107.
    Ring Documentation, Release1.10 6.8 Using This in the class region as Self The class region is the region that comes after the class name and before any method. Now 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 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. 6.8. Using This in the class region as Self 74
  • 108.
    Ring Documentation, Release1.10 6.9 Default value for object attributes is NULL Starting from Ring 1.8 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 In previous versions of Ring, trying to access the object attribute before assigning a value to it Will lead to runtime error and you can’t check it using isnull() The only way was assigning a value or using try/catch/end We changed this behavior so we can have full control in seamless way. 6.10 The For Loops uses the local scope In 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 6.9. Default value for object attributes is NULL 75
  • 109.
    Ring Documentation, Release1.10 ? 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 6.11 Merge binary characters From Ring 1.0 we can create binary strings and do operations on these strings. Now in 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 ? "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: 6.11. Merge binary characters 76
  • 110.
    Ring Documentation, Release1.10 Weo Weo 3 W All String 12 First Part 4 Second Part 4 } Third Part 4 All String 12 1 1 6.12 FoxRing Library Developer: Jose Rosado A class with some of the functions I used in FoxPro Example: Load "foxring.ring" mf = new frFunctions ? mf.frAbs(-45) ? mf.frAbs(10-30) ? mf.frAbs(30-10) ? mf.frTransform(" Ring is a good language ", "@! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") ? mf.frAllTrim(" Ring is a good language ", Null) Output: 45 20 20 RING IS A GOOD LANGUAGE Ring is a good language 6.13 Better Form Designer 1. Layout Control - Display the control name when loading forms. 2. Button Control - Display the button images written using relative path. 3. Table Control - Display the control name when loading forms. 4. Better behavior in “Bring to front” and “Send to back” operations. 5. New buttons are added to the toolbar (Duplicate, Bring to front, Send to back, Delete). 6. Using layouts in (Menubar designer, Window Flags window, Selecting Objects window). 6.12. FoxRing Library 77
  • 111.
    Ring Documentation, Release1.10 7. Better behavior for displaying the properties window when changing the selected objects. 8. New buttons are added to move and resize multiple selection of objects. 9. Window Properties - Add button to select the layout. 10. Opening forms and switching between files is faster. 11. Objects Order window. 12. Select Objects window. 13. When we change the control name, the name will be updated in layout objects. 6.14 Better Cards Game The Cards game is updated and we can play with the Computer 6.15 Better RingQt • The next classes are added to RingQt 1. QTabBar 2. QFile 3. QFileDevice 4. QStandardPaths 5. QDir 6. QQuickWidget 7. QQmlError 6.14. Better Cards Game 78
  • 112.
    Ring Documentation, Release1.10 8. QScrollBar • RingQt for Android is updated to support modern versions of Qt Tested using 1. Qt 5.5.1 2. Qt 5.9.5 3. Qt 5.11.0 • In RingQt for Android, The Ring Object File (ringo) will be executed directly from resources. 6.16 Better Code Generator For Extensions New Option: StaticMethods Starting from Ring 1.8 the code generator support the staticmethods option. So the code generator can know that the class doesn’t need an object to call the methods. Example: <class> name: QStandardPaths para: void nonew staticmethods </class> QString displayName(QStandardPaths::StandardLocation type) QString findExecutable(QString executableName, QStringList paths)) 6.17 Better Ring Compiler and VM 1. Better loading for files in relative paths 2. Code Optimization for eval() function 3. Better Memory Pool 4. 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: 6.16. Better Code Generator For Extensions 79
  • 113.
    Ring Documentation, Release1.10 Start the test! Let us try having an error Line 1 Error (R24) : Using uninitialized variable : x in file Ring_EmbeddedCode End of test! 5. 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 6. Better code (faster) for the main loop, special loop for eval() function. 7. Better code (faster) for tracking C pointers to avoid using NULL pointers. 8. Better code (faster) for getting the self object using braces. 6.18 Notes to extensions creators If you have created new extensions for Ring in the C/C++ languages. You have to rebuild your extension (Generate the DLL file again using Ring 1.8 header files) before usage with Ring 1.8 Because we changed the internal structure of the VM, but no changes to the code are required. just rebuild. 6.18. Notes to extensions creators 80
  • 114.
    CHAPTER SEVEN WHAT IS NEWIN RING 1.7? In this chapter we will learn about the changes and new features in Ring 1.7 release. 7.1 List of changes and new features Ring 1.7 comes with many new features! • New Command: Load Package • ringvm_see() and ringvm_give() functions • ring_state_new() and ring_state_mainfile() functions • Better Trace Library • Better Ring Notepad • Better RingQt • Better Ring2EXE • Better RingZip • Better Documentation • Better Ring VM • RingLibuv Extension 7.2 New Command: 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 Now we have the “Load Package” command too 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 81
  • 115.
    Ring Documentation, Release1.10 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 7.3 ringvm_see() and ringvm_give() functions Using the ringvm_see() function we can redefine the behavior of the See command Also we can use ring_see() to have the original behavior Example: see "Hello world" + nl see 123 + nl see ["one","two","three"] see new point {x=10 y=20 z=30} func ringvm_see t ring_see("We want to print: ") ring_See(t) class point x y z Output: We want to print: Hello world We want to print: 123 We want to print: one two three We want to print: x: 10.000000 y: 20.000000 z: 30.000000 Using the ringvm_give() function we can redefine the behavior of the Give command Also we can use ring_give() to have the original behavior 7.3. ringvm_see() and ringvm_give() functions 82
  • 116.
    Ring Documentation, Release1.10 Example: see "Name: " give name see "Hello " + name func ringvm_give see "Mahmoud" + nl return "Mahmoud" Output: Name: Mahmoud Hello Mahmoud 7.4 ring_state_new() and ring_state_mainfile() functions 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. 7.5 Better Trace Library The Trace library is updated, In the Debugger at break points we have now the “callstack” command This command will print the functions call stack. Example: load "tracelib.ring" func main ? "Hello from main!" test1() func test1 ? "Hello from test1!" test2() func test2 ? "Hello from test2!" test3() func test3 ? "Hello from test3!" breakpoint() 7.4. ring_state_new() and ring_state_mainfile() functions 83
  • 117.
    Ring Documentation, Release1.10 7.6 Better Ring Notepad Ring Notepad comes with the next updates 1. Support *.cf extension 2. Using Hash function (SHA256) for better “Save Changes?” message 3. Ring Notepad - X Button - Ask for saving changes? 7.7 Better RingQt The next classes are added to RingQt 1. QStackedWidget 2. QCalendarWidget 3. QOpenGLFunctions 4. QOpenGLContext 5. QSurfaceFormat 6. QOpenGLWidget 7. QOpenGLVersionProfile 8. QOpenGLFunctions_3_2_Core 9. QVector2D 10. QVector3D 11. QVector4D 7.6. Better Ring Notepad 84
  • 118.
    Ring Documentation, Release1.10 12. QQuaternion 13. QMatrix4x4 14. QOpenGLPaintDevice 15. QPaintDevice 16. QOpenGLTimerQuery 17. QOpenGLDebugLogger 18. QOpenGLFramebufferObject 19. QOpenGLVertexArrayObject 20. QOpenGLBuffer 21. QOpenGLShaderProgram 22. QOpenGLShader 23. QOpenGLTexture 7.8 Better Ring2EXE Ring2EXE is updated to works as expected when we don’t have a C/C++ compiler Where we can distribute applications and get (exe file and ringo file) in this case. 7.9 Better RingZip The library is updated to support extracting files contains sub folders! 7.10 Better Documentation 1. RingQt Classes Chapter - The classes are sorted. 7.11 Better Ring VM 1. Better Error Message 2. List2Str() function support lists contains numbers 3. Correct support for numbers contains _ as separator 4. Creating lists without variables (statement –> Expression –> List) 5. IsNULL() - Not case sensitive - treat Null and null like NULL 6. Support adding the Self object to an attribute in this object 7. Using ‘:’ operator then keyword will create lower case literal 8. Printing objects - respect decimals() function 9. When literal is not closed - determine the start of the literal 7.8. Better Ring2EXE 85
  • 119.
    Ring Documentation, Release1.10 10. Better message when printing objects contains lists 11. VarPtr() - Support getting a pointer to variables in the local scope 12. replace performance instructions with normal instructions when creating new threads 7.12 RingLibuv Extension Ring 1.7 comes with the RingLibuv extension Libuv is a multi-platform support library with a focus on asynchronous I/O. Example (Events Loop): load "libuv.ring" counter = 0 idler = NULL func main idler = new_uv_idle_t() uv_idle_init(uv_default_loop(), idler) uv_idle_start(idler, "wait()") ? "Idling..." uv_run(uv_default_loop(), UV_RUN_DEFAULT); uv_loop_close(uv_default_loop()); destroy_uv_idle_t(idler) func wait counter++ if counter >= 100000 uv_idle_stop(idler) ok Output: Idling... Example (Server): load "libuv.ring" load "objectslib.ring" ? "Testing RingLibuv - Server Side - Using Classes" open_object(:MyServer) class MyServer from ObjectControllerParent DEFAULT_PORT = 13370 DEFAULT_BACKLOG = 1024 addr = new_sockaddr_in() server = NULL client = NULL myloop = NULL func start myloop = uv_default_loop() 7.12. RingLibuv Extension 86
  • 120.
    Ring Documentation, Release1.10 server = new_uv_tcp_t() uv_tcp_init(myloop, server) uv_ip4_addr("127.0.0.1", DEFAULT_PORT, addr) uv_tcp_bind(server, addr, 0) r = uv_listen(server, DEFAULT_BACKLOG, Method(:newconnection) ) if r ? "Listen error " + uv_strerror(r) return 1 ok uv_run(myloop, UV_RUN_DEFAULT) destroy_uv_tcp_t(server) destroy_uv_sockaddr_in(addr) func newconnection ? "New Connection" aPara = uv_Eventpara(server,:connect) nStatus = aPara[2] if nStatus < 0 ? "New connection error : " + nStatus return ok client = new_uv_tcp_t() uv_tcp_init(myloop, client) if uv_accept(server, client) = 0 uv_read_start(client, uv_myalloccallback(), Method(:echo_read)) ok func echo_read aPara = uv_Eventpara(client,:read) nRead = aPara[2] buf = aPara[3] if nRead > 0 req = new_uv_write_t() wrbuf = uv_buf_init(get_uv_buf_t_base(buf), nread) uv_write(req, client, wrbuf, 1, Method(:echo_write)) ? uv_buf2str(wrbuf) message = "message from the server to the client" buf = new_uv_buf_t() set_uv_buf_t_len(buf,len(message)) set_uv_buf_t_base(buf,varptr("message","char *")) uv_write(req, client, buf, 1, Method(:echo_write)) ok func echo_write aPara = uv_Eventpara(client,:read) req = aPara[1] Output: When we run the client, We will see the message “New Connection” Then the message “hello from the client” Testing RingLibuv - Server Side - Using Classes New Connection hello from the client Example (Using Threads): 7.12. RingLibuv Extension 87
  • 121.
    Ring Documentation, Release1.10 load "libuv.ring" load "objectslib.ring" ? "Testing RingLibuv - Threads - Using Classes" open_object(:MyThreads) class MyThreads from ObjectControllerParent func Start one_id = new_uv_thread_t() two_id = new_uv_thread_t() uv_thread_create(one_id, Method(:One)) uv_thread_create(two_id, Method(:Two)) uv_thread_join(one_id) uv_thread_join(two_id) destroy_uv_thread_t(one_id) destroy_uv_thread_t(two_id) func one ? "Message from the First Thread!" func Two ? "Message from the Second Thread!" Output: Testing RingLibuv - Threads - Using Classes Message from the First Thread! Message from the Second Thread! For more information about this extension (RingLibuv) check the chapter: Using RingLibuv 7.12. RingLibuv Extension 88
  • 122.
    CHAPTER EIGHT WHAT IS NEWIN RING 1.6? In this chapter we will learn about the changes and new features in Ring 1.6 release. 8.1 List of changes and new features Ring 1.6 comes with many new features! • Employee Application • New Tool: Ring2EXE • Better Ring For Android • New Tool : Folder2qrc • Better Scripts for building Ring • RingConsoleColors Extension • RingMurmurHash Extension • Better Ring Notepad • Better RingQt • Better StdLib • Better RingVM • Better RingREPL • Using Tab instead of char(9) • Using CR as Carriage return • Using the ! operator as not • Using && and || operators • Using ? to print expression then new line 8.2 Employee Application The Employee application is added to ring/applications Developer: Ahmed Hassouna 89
  • 123.
    Ring Documentation, Release1.10 8.3 New Tool: Ring2EXE In 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 and Mobile devices Read the chapter “Distributing Ring Applications using Ring2EXE” for more information! 8.4 Better Ring For Android Ring For Android (using RingQt) is updated to use the Ring Object File ( *.ringo ) instead of using many source code files ( *.ring ) The next screen shot is an example of building the cards game for Android We are using cards.ringo instead of cards.ring If you have large project (many *.ring files) it will use only one *.ringo file. 8.3. New Tool: Ring2EXE 90
  • 124.
    Ring Documentation, Release1.10 To prepare Qt project to distribute RingQt application for Mobile use Ring2EXE Example ring2exe cards.ring -dist -mobileqt Example (2) ring2exe formdesigner.ring -dist -mobileqt 8.4. Better Ring For Android 91
  • 125.
    Ring Documentation, Release1.10 8.5 New Tool: 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! 8.6 Better Scripts for building Ring Ring 1.6 comes with better scripts for building Ring from source code. The updates are tested on 32bit and 64bit systems on Windows, Linux (Ubuntu,Fedora) and macOS. The scripts for Windows are updated to find the Visual C/C++ compiler based on your Visual Studio version. 8.7 RingConsoleColors Extension Using the RingConsoleColors extension we can easily change the colors used in our console applications For more information check the RingConsoleColors chapter in the documentation. 8.5. New Tool: Folder2qrc 92
  • 126.
    Ring Documentation, Release1.10 8.8 RingMurmurHash Extension Ring 1.6 comes with the RingMurmurHash extension! Developer: Hassan Ahmed Example: load "murmurhashlib.ring" key = "Ring Language" see murmurhash3_x86_32(key, 0, 0) + nl // Output: 1894444853 see murmurhash3_x86_32(key, 0, 1) + nl // Output: 70eaef35 For more information check the RingMurmurHash chapter in the documentation. 8.9 Better Ring Notepad Ring Notepad comes with the next updates 1. Automatic setting for the Main File when we Run the application (using the Main file buttons). 2. Main File - Automatic save before running. 3. When we run GUI application - don’t change the focus to the text box used for the input in the Output Window. 4. A button and option to run web applications For Windows users, Ring 1.6 comes with Apache Web server! We can run any web application from any folder directly without doing any configuration. 8.8. RingMurmurHash Extension 93
  • 127.
    Ring Documentation, Release1.10 5. Tools - Operating System - Terminal (Command Prompt) & Files Manager (Explorer). So we can quickly open the Command Prompt or the Explorer at the application folder. 8.9. Better Ring Notepad 94
  • 128.
    Ring Documentation, Release1.10 6. Support *.sh & *.bat extensions. 7. New Menu: Distribute 8.10 Better RingQt RingQt comes with the next updates 1. QAllEvents - getkeytext() Method 2. QSQLQuery - exec_2() Method 3. QDockWidget Events 4. AppFile() Function 5. IsMobile() Function 8.10. Better RingQt 95
  • 129.
    Ring Documentation, Release1.10 6. QRegion Class 7. QCoreApplication class 8.11 Better StdLib StdLib comes with the next updates 1. Factors() function is updated (Return the output instead of printing it) 2. Palindrome() function is updated (Return the output instead of printing it) 3. Using stdlibcore.ring we can use the StdLib functions (Without Classes) Also this is useful when developing standalone console applications Because using stdlib.ring (functions & classes) will load libraries like RingLibCurl, RingOpenSSL, etc. 4. New Functions • SystemSilent(cCommand) Function : Execute system commands without displaying the output. • OSCreateOpenFolder(cFolder) : Create folder then change the current folder to this new folder • OSCopyFolder(cParentFolder,cFolderNameToCopy) : Copy folder to the current directory • OSDeleteFolder(cFolder) : Delete Folder • OSCopyFile(cFileName) : Copy File to the current directory • OSDeleteFile(cFileName) : Delete File • OSRenameFile(cOldFileName,cNewFileName) : Rename file 8.12 Better RingVM RingVM comes with the next updates 1. Support using many getter methods in Expressions 2. Support using this & self in setter/getter/normal methods without calling setter/getter methods. 3. TempName() function is updated (Better Code) 4. ExeFileName() function is updated (Better Code) 5. Private Attributes - Support re-usage in the class region (After the keyword private) 6. Ring API : ring_scanner_runobjstring() 7. ring_state_setvar() function 8.13 Better RingREPL RingREPL comes with the next updates 1. RingREPL will get command line parameters to determine the style. 2. Setting RingREPL Style based on Ring Notepad Style. 8.11. Better StdLib 96
  • 130.
    Ring Documentation, Release1.10 8.14 Using Tab instead of char(9) The variable Tab is defined to be used instead of char(9) Example (1): see :one + nl + tab + :two + nl + tab + tab + :three Output: one two three You can change the variable to another value Example (2): tab = " " see :one + nl + tab + :two + nl + tab + tab + :three Output: one two three 8.15 Using CR as Carriage return The next example count from 1 to 10 in the same line during 10 seconds load "stdlibcore.ring" for x = 1 to 10 see x sleep(1) see cr next 8.16 Using the ! operator as not We have = and != in the Ring language But for the logical operators we have and, or & not Now we can use the ! operator as not Example: if ! false see "True!" + nl ok Output True! 8.17 Using && and || operators In Ring we have the next keywords for the logical operations 8.14. Using Tab instead of char(9) 97
  • 131.
    Ring Documentation, Release1.10 • and • or • not Now we have also the next operators • && • || • ! Example: if one() and two() see "Test1 - Fail" + nl else see "Test1 - Pass" + nl ok if two() or one() see "Test2 - Pass" + nl else see "Test2 - Fail" + nl ok if one() && two() see "Test3 - Fail" + nl else see "Test3 - Pass" + nl ok if two() || one() see "Test4 - Pass" + nl else see "Test4 - Fail" + nl ok func one return True func two return False Output: Test1 - Pass Test2 - Pass Test3 - Pass Test4 - Pass 8.18 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 8.18. Using ? to print expression then new line 98
  • 132.
    Ring Documentation, Release1.10 ? x next Output: Hello, World! 1 2 3 4 5 6 7 8 9 10 8.18. Using ? to print expression then new line 99
  • 133.
    CHAPTER NINE WHAT IS NEWIN RING 1.5? In this chapter we will learn about the changes and new features in Ring 1.5 release. 9.1 List of changes and new features Ring 1.5 comes with many new features! • Video-Music-Player Application • Windows StartUp Manager Application • Calculator Application • Better Ring Notepad • Better StdLib • Better WebLib • Better RingQt • Better Objects Library • RingFreeGLUT Extension • RingOpenGL Extension • Better Code Generator for Extensions • Better Documentation Generator for Extensions • Ring VM - Tracing Functions • Trace Library and Interactive Debugger • More Syntax Flexibility • Type Hints Library • Better Quality 9.2 Video-Music-Player Application The Video-Music-Player application is added to the Applications folder. Screen Shot: 100
  • 134.
    Ring Documentation, Release1.10 9.3 Windows StartUp Manager Application The Windows StartUp Manager URL : https://github.com/ring-lang/WinStartupManager Screen Shot: 9.3. Windows StartUp Manager Application 101
  • 135.
    Ring Documentation, Release1.10 9.4 Calculator Application The Calculator application is added to the Applications folder. Screen Shot: 9.5 Better Ring Notepad 1. Ring Notepad is updated to include some new styles and the Main File ToolBar The idea of the Main File ToolBar is to determine the main file in the project When the project contains many source code files This way you 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: 9.4. Calculator Application 102
  • 136.
    Ring Documentation, Release1.10 9.5. Better Ring Notepad 103
  • 137.
    Ring Documentation, Release1.10 2. The output window is updated to display the new lines correctly and contains the “Clear” button. Screen Shot: (3) The Ring Notepad is updated to quickly open and switch between large files while preparing the functions/classes lists in the background. Screen Shot: 9.5. Better Ring Notepad 104
  • 138.
    Ring Documentation, Release1.10 9.6 Better StdLib New Functions • Print2Str() • ListAllFiles() • SystemCmd() 1. The Print2Str() is a new function added to the StdLib Example: load "stdlib.ring" world = "World!" mystring = print2str("Hello, #{world} nIn Year n#{2000+17} n") see mystring + nl Output: Hello, World! In Year 2017 2. The ListAllFiles() is a new function added to the StdLib Using this function we can quickly do a process on a group of files in a folder and it’s sub folders. Example: load "stdlib.ring" aList = ListAllFiles("c:/ring/ringlibs","ring") # *.ring only 9.6. Better StdLib 105
  • 139.
    Ring Documentation, Release1.10 aList = sort(aList) see aList Example: load "stdlib.ring" see listallfiles("b:/ring/ringlibs/weblib","") # All Files 3. The SystemCmd() is a new function added to the StdLib The function will execute a system command like the System() function but will return the output in a string. Example: cYou = SystemCmd("whoami") See "SystemCmd: whoami ====="+ nl + cYou +nl Output: SystemCmd: whoami ===== desktop-umbertoumberto 9.7 Better WebLib The WebLib is updated to include the 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 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) 9.7. Better WebLib 106
  • 140.
    Ring Documentation, Release1.10 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()) Using this feature 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 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 9.7. Better WebLib 107
  • 141.
    Ring Documentation, Release1.10 { 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()) func PrintEvent printer1 = new qPrinter(0) { setoutputformat(1) setoutputfilename("report.pdf") } oView { web.print(printer1) web.show() } system ("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: 9.7. Better WebLib 108
  • 142.
    Ring Documentation, Release1.10 9.8 Better RingQt New classes added to RingQt : • QStringRef • QMutex • QMutexLocker • QBuffer • QBluetoothAddress • QBluetoothDeviceDiscoveryAgent • QBluetoothDeviceInfo • QBluetoothHostInfo • QBluetoothLocalDevice • QBluetoothServer • QBluetoothServiceDiscoveryAgent • QBluetoothServiceInfo • QBluetoothSocket • QBluetoothTransferManager • QBluetoothTransferReply • QBluetoothTransferRequest • QBluetoothUuid 9.8. Better RingQt 109
  • 143.
    Ring Documentation, Release1.10 Example: ### Submits your car VIN - Vehicle Id Number - to the Web Site - vpic.nhtsa.dot.gov - ### Parses XML data returned ### Prints out the car info result load "libcurl.ring" load "guilib.ring" load "stdlib.ring" curl = curl_easy_init() # request = "3G1JC5248YS251015?format=xml" ### VIN - Chevrolet request = "3GYFK62847G247323?format=xml" ### VIN - Cadillac call_type = "decodevinvalues/" url = "https://vpic.nhtsa.dot.gov/api/vehicles/" url_request = url + call_type + request See "URL Request: "+ url_request +nl curl_easy_setopt(curl, curlopt_url, url_request) response = curl_easy_perform_silent(curl); See nl +"Response Raw: "+ response +nl +nl curl_easy_cleanup(curl) xml = new qxmlstreamreader() xml.adddata_2(response) x = new qstringref() while not xml.atend() if xml.error() see xml.errorstring() see nl exit loop ok x = xml.text() if not x.length() = 0 see "Length: " see x.length() +" --- " see "Value: " see x.tostring() see nl ok xml.readnext() end get x ###------------------------------------------ ### Results # # ==>Value: 115 # ==>Value: Results returned successfully # ==>Value: VIN(s): 3G1JC5248YS251015 # ==>Value: 3G1JC5248YS251015 # ==>Value: Sedan/Saloon # ==>Value: 4 # ==>Value: 2200.0 9.8. Better RingQt 110
  • 144.
    Ring Documentation, Release1.10 # ==>Value: 134.25223700841 # ==>Value: 2.2 # ==>Value: 4 # ==>Value: LN2 # ==>Value: CHEVROLET # ==>Value: GENERAL MOTORS LLC # ==>Value: Cavalier # ==>Value: 2000 # ==>Value: Ramos Arzipe # ==>Value: PASSENGER CAR # ==>Value: 4 # ==>Value: In-Line # ==>Value: 1st Row (Driver & Passenger) # ==>Value: Sequential Fuel Injection (SFI) # ==>Value: Mexico # ==>Value: NA # ==>Value: Manual # ==>Value: Body Type: Sedan, 4-6 Window, Notchback (GM codes: 19, 69) # ==>Value: Name Plate: Chevrolet, Pontiac # ==>Value: 0 - VIN decoded clean. Check Digit (9th position) is correct # ==>Value: LAN # ==>Value: 984 # ###----------------------------------------- 9.9 Better Objects Library The function Open_WindowInPackages() is added to the Objects library. The Open_WindowInPackages() function is the same as Open_Window() but takes an extra list that determine the packages to import before opening the window. Syntax: Open_WindowInPackages(cClassName,aPackagesList) Example: The next example from the Form Designer source code, Open the Window Flags window using the open_windowInPackages() function. We determine the class name “WindowFlagsController” and the packages name. The Window Flags window uses the FormDesigner and System.GUI packages. open_windowInPackages(:WindowFlagsController,[ "formdesigner", "System.GUI" ]) 9.10 RingFreeGLUT Extension Ring 1.5 comes with RingFreeGLUT extension to support the FreeGLUT library Example: 9.9. Better Objects Library 111
  • 145.
    Ring Documentation, Release1.10 /* This sample is based on C Tutorials from : http://www.lighthouse3d.com/tutorials/glut-tutorial/ */ 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 9.10. RingFreeGLUT Extension 112
  • 146.
    Ring Documentation, Release1.10 C_INT_GLUT_BITMAP_HELVETICA_12 = 12 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) 9.10. RingFreeGLUT Extension 113
  • 147.
    Ring Documentation, Release1.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 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) func computePos deltaMove 9.10. RingFreeGLUT Extension 114
  • 148.
    Ring Documentation, Release1.10 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() glPushMatrix() glLoadIdentity() 9.10. RingFreeGLUT Extension 115
  • 149.
    Ring Documentation, Release1.10 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 // ----------------------------------- // MOUSE // ----------------------------------- func mouseMove 9.10. RingFreeGLUT Extension 116
  • 150.
    Ring Documentation, Release1.10 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 // all actions are for submenus func processFillMenu 9.10. RingFreeGLUT Extension 117
  • 151.
    Ring Documentation, Release1.10 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 blue = 0.5 off func createPopupMenus 9.10. RingFreeGLUT Extension 118
  • 152.
    Ring Documentation, Release1.10 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) glutIgnoreKeyRepeat(1) glutKeyboardFunc(:processNormalKeys) glutSpecialFunc(:pressKey) glutSpecialUpFunc(:releaseKey) // here are the two new functions glutMouseFunc(:mouseButton) 9.10. RingFreeGLUT Extension 119
  • 153.
    Ring Documentation, Release1.10 glutMotionFunc(:mouseMove) // OpenGL init glEnable(GL_DEPTH_TEST) glEnable(GL_CULL_FACE) // init Menus createPopupMenus() // enter GLUT event processing cycle glutMainLoop() Screen Shots: 9.10. RingFreeGLUT Extension 120
  • 154.
    Ring Documentation, Release1.10 9.11 RingOpenGL Extension Ring 1.5 comes with RingOpenGL and 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 • OpenGL 4.4 • OpenGL 4.5 • OpenGL 4.6 Example: /* This sample is based on C Tutorials from : http://www.wikihow.com/Make-a-Cube-in-OpenGL */ 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 9.11. RingOpenGL Extension 121
  • 155.
    Ring Documentation, Release1.10 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 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 ) 9.11. RingOpenGL Extension 122
  • 156.
    Ring Documentation, Release1.10 glVertex3f( -0.5, -0.5, -0.5 ) glEnd() glFlush() glutSwapBuffers() // ---------------------------------------------------------- // specialKeys() Callback Function // ---------------------------------------------------------- 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) 9.11. RingOpenGL Extension 123
  • 157.
    Ring Documentation, Release1.10 // Pass control to GLUT for events glutMainLoop() // Return to OS Screen Shot: 9.12 Better Code Generator for Extensions The Code Generator is updated to support <constant> type, So we can have constants other than numbers, for example : Strings and Pointers. When we have pointers we can determine the pointer type. To use this feature, before <constant> and </constant> we can use $nDefaultConstantType = C_CONSTANT_TYPE_POINTER $cDefaultConstantPointerType = "void *" The next example from the RingFreeGLUT extension <runcode> $nDefaultConstantType = C_CONSTANT_TYPE_POINTER $cDefaultConstantPointerType = "void" </runcode> <constant> GLUT_STROKE_ROMAN GLUT_STROKE_MONO_ROMAN GLUT_BITMAP_9_BY_15 GLUT_BITMAP_8_BY_13 GLUT_BITMAP_TIMES_ROMAN_10 GLUT_BITMAP_TIMES_ROMAN_24 GLUT_BITMAP_HELVETICA_10 GLUT_BITMAP_HELVETICA_12 9.12. Better Code Generator for Extensions 124
  • 158.
    Ring Documentation, Release1.10 GLUT_BITMAP_HELVETICA_18 </constant> 9.13 Better Documentation Generator for Extensions The documentation generator for extensions is updated to generate a list of constants in the generated documentation The previous versions provides the functions prototype only, Now we have the list of constants too. 9.14 Ring VM - Tracing Functions In Ring 1.5 the next functions are added to Ring VM • RingVM_SetTrace(cCode) • RingVM_TraceData() –> aDataList • RingVM_TraceEvent() –> nTraceEvent • RingVM_TraceFunc() –> cCode • RingVM_ScopesCount() –> nScopes • RingVM_EvalInScope(nScope,cCode) • RingVM_PassError() • RingVM_HideErrorMsg(lStatus) • RingVM_CallFunc(cFuncName) Example: load "tracelib.ring" ringvm_settrace("mytrace()") see "Hello, world!" + nl see "Welcome" + nl see "How are you?" +nl mytest() new myclass { mymethod() } func mytest see "Message from mytest" + nl func mytrace see "====== The Trace function is Active ======" + nl + "Trace Function Name : " + ringvm_TraceFunc() + nl + "Trace Event : " switch ringvm_TraceEvent() on TRACEEVENT_NEWLINE see "New Line" on TRACEEVENT_NEWFUNC see "New Function" on TRACEEVENT_RETURN see "Return" on TRACEEVENT_ERROR see "Error" on TRACEEVENT_BEFORECFUNC see "Before C Function" on TRACEEVENT_AFTERCFUNC see "After C Function" off 9.13. Better Documentation Generator for Extensions 125
  • 159.
    Ring Documentation, Release1.10 see nl + "Line Number : " + ringvm_tracedata()[TRACEDATA_LINENUMBER] + nl + "File Name : " + ringvm_tracedata()[TRACEDATA_FILENAME] + nl + "Function Name : " + ringvm_tracedata()[TRACEDATA_FUNCNAME] + nl + "Method or Function : " if ringvm_tracedata()[TRACEDATA_METHODORFUNC] = TRACEDATA_METHODORFUNC_METHOD see "Method" else if ringvm_tracedata()[TRACEDATA_FUNCNAME] = NULL see "Command" else see "Function" ok ok see nl + Copy("=",42) + nl class myclass func mymethod see "Message from mymethod" + nl Output: ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : After C Function Line Number : 3 File Name : test1.ring Function Name : ringvm_settrace Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 5 File Name : test1.ring Function Name : Method or Function : Command ========================================== Hello, world! ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 6 File Name : test1.ring Function Name : Method or Function : Command ========================================== Welcome ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 7 File Name : test1.ring Function Name : Method or Function : Command ========================================== How are you? 9.14. Ring VM - Tracing Functions 126
  • 160.
    Ring Documentation, Release1.10 ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 8 File Name : test1.ring Function Name : Method or Function : Command ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Function Line Number : 8 File Name : test1.ring Function Name : mytest Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 12 File Name : test1.ring Function Name : mytest Method or Function : Function ========================================== Message from mytest ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 14 File Name : test1.ring Function Name : mytest Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : Return Line Number : 8 File Name : test1.ring Function Name : Method or Function : Command ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 9 File Name : test1.ring Function Name : Method or Function : Command ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 43 File Name : test1.ring Function Name : Method or Function : Command ========================================== ====== The Trace function is Active ====== 9.14. Ring VM - Tracing Functions 127
  • 161.
    Ring Documentation, Release1.10 Trace Function Name : mytrace() Trace Event : Before C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : After C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Function Line Number : 9 File Name : test1.ring Function Name : mymethod Method or Function : Method ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 44 File Name : test1.ring Function Name : mymethod Method or Function : Method ========================================== Message from mymethod ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : Return Line Number : 9 File Name : test1.ring Function Name : Method or Function : Command ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : Before C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : After C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() 9.14. Ring VM - Tracing Functions 128
  • 162.
    Ring Documentation, Release1.10 Trace Event : Before C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : After C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 11 File Name : test1.ring Function Name : Method or Function : Command ========================================== 9.15 Trace Library and Interactive Debugger Ring 1.5 comes with the Trace Library and the Interactive Debugger Using this library we can trace events, execute programs line by line, open the Interactive Debugger when an error happens or at breakpoints. Example: 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! 9.15. Trace Library and Interactive Debugger 129
  • 163.
    Ring Documentation, Release1.10 We can print the variables values We can change the variables values then continue execution We can run the Interactive Debugger in the Output Window 9.15. Trace Library and Interactive Debugger 130
  • 164.
    Ring Documentation, Release1.10 9.16 More Syntax Flexibility • Using braces { } in Packages/Classes/Functions Example: load "stdlib.ring" import mypackage new myclass { myfunc() } package mypackage { class myclass { func myfunc { print("Hello, World!n") } } } • Using ‘end’ keyword after Packages/Classes/Functions Example: import mypackage new myclass { myfunc() } 9.16. More Syntax Flexibility 131
  • 165.
    Ring Documentation, Release1.10 package mypackage class myclass def myfunc put "Hello, World!" end end end • Using ‘endpackage’/’endclass’/’endfunc’ keywords after Packages/Classes/Functions Example: import mypackage new myclass { myfunc() } package mypackage class myclass func myfunc see "welcome" + nl endfunc endclass endpackage 9.17 Type Hints Library Ring 1.5 comes with the Type Hints library 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 Example: 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 ; } The library is very powerful and support the User types (Classes) automatically! Example: load "typehints.ring" import mypackage test() { main([:one,:two,:three]) } 9.17. Type Hints Library 132
  • 166.
    Ring Documentation, Release1.10 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 } } } 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 ; } 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). Note: Ring is a dynamic language, No type checking will be done by the compiler. 9.18 Better Quality Based on Ring usage every day in practical projects Ring 1.5 is more stable and more productive! We are adding features based on clear vision and practical needs. Also the documentation is better. 9.19 What is new in Ring 1.5.1? • Better Documentation 9.18. Better Quality 133
  • 167.
    Ring Documentation, Release1.10 • StdLib - Factorial() function update • RingVM - Better code for clearing the stack in the Class Region. • Sample : 3D Cube (OpenGL) + Texture Image using GameLib (RingAllegro) Source Code: load "gamelib.ring" load "opengl21lib.ring" 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) 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) 9.19. What is new in Ring 1.5.1? 134
  • 168.
    Ring Documentation, Release1.10 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) 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() xrot += 0.3 yrot += 0.2 zrot += 0.4 class GraphicsAppBase display event_queue ev timeout timer redraw = true FPS = 60 SCREEN_W = 800 SCREEN_H = 600 KEY_UP = 1 9.19. What is new in Ring 1.5.1? 135
  • 169.
    Ring Documentation, Release1.10 KEY_DOWN = 2 KEY_LEFT = 3 KEY_RIGHT = 4 Key = [false,false,false,false] TITLE = "Graphics Application" func start SetUp() loadResources() eventsLoop() destroy() func setup al_init() 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_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 9.19. What is new in Ring 1.5.1? 136
  • 170.
    Ring Documentation, Release1.10 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) func loadresources func drawScene func destroyResources Screen Shot: 9.19. What is new in Ring 1.5.1? 137
  • 171.
    Ring Documentation, Release1.10 9.20 What is new in Ring 1.5.2? • Documentation - Chapter “Applications developed in little hours” is updated • Ring Notepad - Display programs output in the output window on all platforms • Form Designer - Help Menu - Open CHM/PDF files without displaying the console window • Form Designer - Better response to Resize/Move Events when moving the Mouse quickly • Form Designer - New/Open/Save As, will open the Controller class in Ring Notepad • Form Designer - Added “Close Form” option to the file menu • Ring Notepad - Run, will save the current file (Also the opened Form) automatically • GetQuotesHistory Application - Updated to work on MacOS X and Qt 5.2 • Calculator Application - Updated to include more features! • RingVM - Classification for Environment Errors (Check Chapter : Language Reference) • RingQt - New methods added to QAllEvents for faster Events execution • RingQt - Fusion Black Style - Better colors for disabled controls • Scripts - For building Ring on Fedora Linux (Check Chapter : Building From Source Code) Screen Shot: 9.20. What is new in Ring 1.5.2? 138
  • 172.
    Ring Documentation, Release1.10 9.21 What is new in Ring 1.5.3? • Form Designer : Close Action will notify Ring Notepad to be able to open the Form again • Form Designer : Save Action will open the controller class in Ring Notepad • Form Designer : Keep current control selected when selecting many controls using CTRL Key • Form Designer : Nice form back color when used in Ring Notepad (Style: Modern Black) • RingOpenSSL : Updated to support newer versions like OpenSSL 1.1 • Building Scripts : Updated to work on Fedora 26 (64bit) • OpenGL : New Sample - Many Cubes (samples/3D/manycubes) Screen Shot: 9.21. What is new in Ring 1.5.3? 139
  • 173.
    Ring Documentation, Release1.10 • RingQt : Add QDateTime Class • RingQt : New methods added to QMenu and QCursor Classes Example: load "guilib.ring" new qApp { win = new qwidget() { setwindowtitle("Context Menu") resize(400,400) myfilter = new qAllEvents(win) { setContextmenuEvent("mymenu()") } installeventfilter(myfilter) show() } exec() } func mymenu new qMenu(win) { 9.21. What is new in Ring 1.5.3? 140
  • 174.
    Ring Documentation, Release1.10 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()) } • Compiler : Support using _ in numbers Example: x = 1_000_000 see type(x)+nl see x+1+nl Output: NUMBER 100000001 • Compiler : Support using f after numbers Example: x = 19.99f see type(x) + nl Output: NUMBER • Google API Shortener Application Screen Shots: 9.21. What is new in Ring 1.5.3? 141
  • 175.
    Ring Documentation, Release1.10 • TicTacToe 3D Game Screen Shot: 9.22 What is new in Ring 1.5.4? • CalmoSoft Fifteen Puzzle Game 3D • Ring Notepad - New Styles 9.22. What is new in Ring 1.5.4? 142
  • 176.
    Ring Documentation, Release1.10 • Ring Notepad - Better Toolbar Style • Ring Notepad - View Modes • Ring Notepad - QPlainTextEdit - don’t set back color for the scroll bars • Ring Notepad - Style Fusion (White) - use Silver color for comments • Ring Notepad - Tab and Shift-Tab - Indent multiple lines • Form Designer - Better Toolbar Style • Form Designer - Nice backcolor for Window Flags and Menubar Designer • Form Designer - Default back color for controls • RingQt - Added grab() and windowHandle() methods to QWidget class • RingQt - Added new methods to QPixmap Class • RingQt - Added Classes :- – QScreen – QWindow – QGuiApplication – QTextBrowser • Code Generator for Extensions - Nonew Option - Support Parent Class • Ring VM - Internal Implementation - Pass state to Strings and Lists objects • Ring VM - Garbage Collector - Memory Pool for Small Objects • Ring VM - Better code for Saving/Restoring the State 9.22. What is new in Ring 1.5.4? 143
  • 177.
    CHAPTER TEN WHAT IS NEWIN RING 1.4? In this chapter we will learn about the changes and new features in Ring 1.4 release. 10.1 List of changes and new features Ring 1.4 comes with many new features • Change: Basic Extensions are separated from RingVM • The Natural Library • New Style is added to Ring Notepad • RingREPL • Convert between Numbers and Bytes • Better StdLib • Better WebLib • Better RingQt • Qt Class Convertor 10.2 Change: Basic Extensions are separated from RingVM In Ring 1.4 the next libraries are separated from RingVM • RingODBC • RingMySQL • RingSQLite • RingOpenSSL • RingInternet To use these libraries, Use the Load command. load "odbclib.ring" # use ODBC Functions load "mysqllib.ring" # use MySQL Functions 144
  • 178.
    Ring Documentation, Release1.10 load "sqlitelib.ring" # use SQLite Functions load "openssllib.ring" # use OpenSSL Functions ( Hash and Security functions) load "internetlib.ring" # use Internet Functions ( Download() and SendEmail() ) If you will use all of these libraries, You can just use stdlib.ring And the stdlib.ring will load odbclib.ring, mysqllib.ring, sqlitelib.ring, opensslib.ring and internetlib.ring files. load "stdlib.ring" 10.3 The Natural Library Ring 1.4 comes with the Natural Library to quickly define a language that contains a group of commands. 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. 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! 10.3. The Natural Library 145
  • 179.
    Ring Documentation, Release1.10 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) 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 10.3. The Natural Library 146
  • 180.
    Ring Documentation, Release1.10 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) } ]) 10.4 New Style is added to Ring Notepad In Ring Notepad - From View - Styles - Select the (Modern) Style Screen Shot: 10.4. New Style is added to Ring Notepad 147
  • 181.
    Ring Documentation, Release1.10 10.5 RingREPL In the application folder, You will find RingREPL (Read-Eval-Print-Loop) Also you can run it from Ring Notepad (Menubar - Tools) Screen Shot: 10.6 Convert between Numbers and Bytes Ring 1.4 comes with the next functions to convert between Numbers and Bytes. • Int2Bytes() • Float2Bytes() • Double2Bytes() • Bytes2Int() • Bytes2Float() 10.5. RingREPL 148
  • 182.
    Ring Documentation, Release1.10 • Bytes2Double() Example: 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 10.7 Better StdLib The StdLib is updated to include the next functions • FSize() The print() function is updated to accept local variables. load "stdlib.ring" func main print("Enter your name : ") ; Name = getString() ; print( "Hello : #{Name} ") ; return ; 10.8 Better WebLib The web library is updated • Provide better error message 1. Error (WebLib-1) : REQUEST_METHOD is empty ! - Run this script from the browser 2. Error (DataLib-1) : Can’t connect to the database server! • Better Template() function - can accept NULL instead of object as the second paramter. html(template("main.rhtml",NULL)) • The Form Class is updated to support the “target” attribute. BootStrapWebPage() { Title = "The Ring Programming Language" html(template("main.rhtml",NULL)) 10.7. Better StdLib 149
  • 183.
    Ring Documentation, Release1.10 div { classname = :container div { id = "div3" color = "black" backgroundcolor = "white" width = "100%" form { method = "POST" Action = website Target = "codeoutput" input { type="hidden" name="page" value=1 } Table { style = stylewidth("100%") + stylegradient(3) TR { TD { align="center" WIDTH="10%" text("Code :") } TD { html(` <textarea name = "cCode" rows="5" style="width : 100%; "> See "Hello, World!" + nl </textarea>`) } } } Input { type = "submit" classname="btn btn-primary btn-block" value = "Execute" } Table { style = stylewidth("100%") + stylegradient(34) TR { TD { align="center" WIDTH="10%" text("Output :") } TD { html(` <iframe name="codeoutput" width="100%" style="background-color:white;"> </iframe>`) } } } 10.8. Better WebLib 150
  • 184.
    Ring Documentation, Release1.10 } } } html(template("footer.rhtml",NULL)) } 10.9 Better RingQt The next functions are added to RingQt • SetDialogIcon(cIconFile) • MsgInfo(cTitle,cMessage) • ConfirmMsg(cTitle,cMessage) • InputBox(cTitle,cMessage) • InputBoxInt(cTitle,cMessage) • InputBoxNum(cTitle,cMessage) • InputBoxPass(cTitle,cMessage) The next classes are added to RingQt • QToolButton • QSerialPort • QSerialPortInfo 10.10 Qt Class Convertor Ring 1.4 comes with a simple tool that help in porting Qt classes to RingQt. You will find it in ring/samples/tools/QtClassConverter Online : https://github.com/ring-lang/ring/tree/master/samples/tools/QtClassConverter Screen Shot: 10.9. Better RingQt 151
  • 185.
    Ring Documentation, Release1.10 10.11 What is new in Ring 1.4.1? Ring 1.4.1 comes with the next changes • Better Scripts for Building from Source Code • Better Colors for the Modern Style in Ring Notepad • Better StdLib • Better RingQt • New Sample : Sixteen Puzzle The scripts are updated for building from source code. Tested using Windows, Ubuntu Linux, Linux Mint and MacOS X. Screen Shot: 10.11. What is new in Ring 1.4.1? 152
  • 186.
    Ring Documentation, Release1.10 In Ring Notepad - the (Modern) Style colors are updated Screen Shot: The StdLib is updated to include the next functions • TrimLeft() • TrimRight() • TrimAll() • EpochTime() 10.11. What is new in Ring 1.4.1? 153
  • 187.
    Ring Documentation, Release1.10 The next functions are updated to display the dialogs on the top of other windows. • SetDialogIcon(cIconFile) • MsgInfo(cTitle,cMessage) • ConfirmMsg(cTitle,cMessage) • InputBox(cTitle,cMessage) • InputBoxInt(cTitle,cMessage) • InputBoxNum(cTitle,cMessage) • InputBoxPass(cTitle,cMessage) The Sixteen Puzzle is added to the Applications folder. Screen Shot: 10.11. What is new in Ring 1.4.1? 154
  • 188.
    Ring Documentation, Release1.10 10.11. What is new in Ring 1.4.1? 155
  • 189.
    CHAPTER ELEVEN WHAT IS NEWIN RING 1.3? In this chapter we will learn about the changes and new features in Ring 1.3 release. 11.1 List of changes and new features Ring 1.3 comes with many new features • Better RingQt • Better Ring Notepad • Ring mode for Emacs Editor • Better StdLib • Better Loop/Exit Command • New Functions • Return Self by Reference • Using ‘<’ and ‘:’ operators as ‘from’ keyword • Embedding Ring in Ring without sharing the State • RingZip Library • Form Designer 11.2 Better RingQt (1) Another version of QPixMap class is added (QPixMap2) which takes (int width,int height) during object init. Example: Load "guilib.ring" New qapp { win1 = new qwidget() { setwindowtitle("Drawing using QPixMap") setgeometry(100,100,500,500) label1 = new qlabel(win1) { setgeometry(10,10,400,400) settext("") 156
  • 190.
    Ring Documentation, Release1.10 } imageStock = new qlabel(win1) { image = new qPixMap2(200,200) color = new qcolor() { setrgb(255,255,255,255) } pen = new qpen() { setcolor(color) setwidth(10) } new qpainter() { begin(image) setpen(pen) drawline(0,0,200,200) drawline(200,0,0,200) endpaint() } setpixmap(image) } show() } exec() } Screen Shot: 11.2. Better RingQt 157
  • 191.
    Ring Documentation, Release1.10 2. The Objects Library is updated to include the next functions • Last_WindowID() • Open_WindowNoShow() • Open_WindowAndLink() Also the class name (WindowViewBase) is changed to (WindowsViewParent). In The next code for example the Open_WindowAndLink() will create an object from the SecondWindowController Class Then will add the Method SecondWindow() to the FirstWindowController Class Also will add the Method FirstWindow() to the SecondWindowController Class So the SendMessage() method in FirstWindowController class can use the SecondWindow() method to access the object. class firstwindowController from windowsControllerParent oView = new firstwindowView func OpenSecondWindow Open_WindowAndLink(:SecondWindowController,self) 11.2. Better RingQt 158
  • 192.
    Ring Documentation, Release1.10 func SendMessage if IsSecondWindow() SecondWindow().setMessage("Message from the first window") ok func setMessage cMessage oView.Label1.setText(cMessage) 3. The next classes are added to RingQt • QPixMap2 • QScrollArea • QSplitter • QCompleter • QCompleter2 • QCompleter3 • QProcess • QMdiArea • QMdiSubWindow • QCursor • QListView • QDesktopServices 4. Many constants are defined in qt.rh (loaded by guilib.ring) 5. 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/applications/formdesigner/tests/indexstart/indexstartView.ring 11.2. Better RingQt 159
  • 193.
    Ring Documentation, Release1.10 2. https://github.com/ring-lang/ring/blob/master/applications/formdesigner/tests/indexstart/indexstartController.ring 11.3 Better Ring Notepad 1. Using QPlainTextEdit instead of QTextEdit 2. Displaying the line number for each line in the source code file. Screen Shot: 3. Auto-Complete for Ring functions names, classes and words in the opened file. 11.3. Better Ring Notepad 160
  • 194.
    Ring Documentation, Release1.10 4. Functions and Methods List 11.3. Better Ring Notepad 161
  • 195.
    Ring Documentation, Release1.10 5. Output Window 6. Classes List 11.3. Better Ring Notepad 162
  • 196.
    Ring Documentation, Release1.10 7. Change the Current Style 11.4 Ring mode for Emacs Editor Ring 1.3 comes with Ring mode for Emacs Editor Screen Shot: 11.4. Ring mode for Emacs Editor 163
  • 197.
    Ring Documentation, Release1.10 11.5 Better StdLib The StdLib is updated to include the next functions • SplitMany() • JustFilePath() • JustFileName() 11.6 Better Loop|Exit Command The Loop|Exit command is updated to accept Expressions after the command (not only numbers). The syntax: Loop|Exit [Number] Changed to Loop|Exit [Expression] Example XLoop = 2 # The outer loop YLoop = 1 # The first inner loop for x = 1 to 10 for y = 1 to 10 see "x=" + x + " y=" + y + nl if x = 3 and y = 5 exit XLoop ok 11.5. Better StdLib 164
  • 198.
    Ring Documentation, Release1.10 next next 11.7 New Functions • PackageName() function • 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 11.8 Return Self by Reference In this release, using Return Self in class methods will return the object by reference. Example: mylist = [new mytest() { see self x = 20 see self }] see mylist class mytest x = 15 func init return self # Return by reference Output x: 15.000000 x: 20.000000 x: 20.000000 11.7. New Functions 165
  • 199.
    Ring Documentation, Release1.10 11.9 Using ‘<’ and ‘:’ operators as ‘from’ keyword In this release of the Ring language we can use the ‘<’ and ‘:’ operators as the ‘from’ keyword Syntax (1): class Cat from Animal Syntax (2): class Cat < Animal Syntax (3): class Cat : Animal 11.10 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 10 20 11.9. Using ‘<’ and ‘:’ operators as ‘from’ keyword 166
  • 200.
    Ring Documentation, Release1.10 11.11 RingZip Library Ring 1.3 comes with the RingZip library for creating, modifying and extracting *.zip files. Example (1): Create myfile.zip contains 4 files load "ziplib.ring" oZip = zip_openfile("myfile.zip",'w') zip_addfile(oZip,"test.c") zip_addfile(oZip,"zip.c") zip_addfile(oZip,"zip.h") zip_addfile(oZip,"miniz.h") zip_close(oZip) Example (2): Extract myfile.zip to myfolder folder. load "ziplib.ring" zip_extract_allfiles("myfile.zip","myfolder") Example (3): Print file names in the myfile.zip load "ziplib.ring" oZip = zip_openfile("myfile.zip",'r') for x=1 to zip_filescount(oZip) see zip_getfilenamebyindex(oZip,x) + nl next zip_close(oZip) Example (4) : Using Classes instead of Functions load "ziplib.ring" new Zip { SetFileName("myfile.zip") Open("w") AddFile("test.c") AddFile("zip.c") AddFile("zip.h") AddFile("miniz.h") Close() } 11.12 Form Designer Ring 1.3 comes with the Form Designer to quickly design your GUI application windows/forms and generate the Ring source code. It’s written in Ring (Around 8000 Lines of code) using Object-Oriented Programming and Meta-Programming. We can run the From Designer from Ring Notepad 11.11. RingZip Library 167
  • 201.
    Ring Documentation, Release1.10 Also we can run the Form Designer in another window. 11.12. Form Designer 168
  • 202.
    CHAPTER TWELVE WHAT IS NEWIN RING 1.2? In this chapter we will learn about the changes and new features in Ring 1.2 release. 12.1 List of changes and new features Ring 1.2 comes with many new features • New Functions • Better Functions • Better Ring Notepad • Better RingQt • Objects Library for RingQt • RingLibCurl • Better Call Command • Using NULL instead of NULLPointer() • Display Warnings Option • Better Quality 12.2 New Functions • PtrCmp() Function is a new function that compare between C pointers like the GUI objects. • PrevFileName() Function is added to return the previous active source file name. • RingVM_CFunctionsList() Function is added to return a list of functions written in C. • RingVM_FunctionsList() Function is added to return a list of functions written in Ring. • RingVM_ClassesList() Function is added to return a list of Classes. • RingVM_PackagesList() Function is added to return a list of Packages. • RingVM_MemoryList() Function is added to return a list of Memory Scopes and Variables. • RingVM_CallList() Function is added to return a list of the functions call list. • RingVM_FilesList() Function is added to return a list of the Ring Files. Example: 169
  • 203.
    Ring Documentation, Release1.10 fp = fopen("ptrcmp.ring","r") fp2 = fp fp3 = fopen("ptrcmp.ring","r") see ptrcmp(fp,fp2) + nl see ptrcmp(fp,fp3) + nl fclose(fp) fclose(fp3) Output: 1 0 Also we can compare between them using the ‘=’ operator Example: fp = fopen("ptrcmp2.ring","r") fp2 = fopen("ptrcmp2.ring","r") fp3 = fp see fp = fp2 see nl see fp = fp3 fclose(fp) fclose(fp2) Output: 0 1 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 12.3 Better Functions The find() function is updated to support searching in lists using C pointers like GUI Objects. The type() function is updated to display the C pointers types (like the GUI Object Class Name). 12.4 Better Ring Notepad The Ring Notepad will save the current line number of opened files to be restored when we switch between files. Also Ring Notepad will ask the user to save the file if the file content is changed when the user switch between files. 12.3. Better Functions 170
  • 204.
    Ring Documentation, Release1.10 12.5 Better RingQt RingQt classes are updated to include methods to get events (The code that will be executed when an event is fired). This is necessary to enable/disable events for some time or to get the events information. For example the next code disable an event then call a method then enable the event again. cEvent = oView.oListResult.getCurrentItemChangedEvent() oView.oListResult.setCurrentItemChangedEvent("") FindValueAction() # Call Method while an event is disabled oView.oListResult.setCurrentItemChangedEvent(cEvent) Also the QAllEvents class is updated where we can set the output from the event function to be true or false using a new method added to the class called setEventOutput. Load "guilib.ring" MyApp = New qApp { win = new qWidget() { setwindowtitle("Hello World") setGeometry(100,100,370,250) lineedit1 = new qlineedit(win) { setGeometry(10,100,350,30) setinputmask("9999;_") oFilter = new qallevents(lineedit1) oFilter.setfocusoutEvent("pMove()") installeventfilter(oFilter) } lineedit2 = new qlineedit(win) { setGeometry(10,150,350,30) } show() } exec() } func pMove win.setWindowTitle("xxxx") oFilter.setEventOutput(False) 12.6 Objects Library for RingQt Ring 1.2 comes with the Objects library for RingQt applications. Instead of using global variables for windows objects and connecting events to objects using the object name, the Objects Library will manage the GUI objects and will provide a more natural API to quickly create one or many windows from the same class and the 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. The Objects Library is designed to be used with the MVC Design Pattern. The Objects Library is merged in RingQt so you can use it directly when you use RingQt Example : load "guilib.ring" new qApp { 12.5. Better RingQt 171
  • 205.
    Ring Documentation, Release1.10 open_window( :MainWindowController ) exec() } class MainWindowController from WindowsControllerParent oView = new MainWindowView func SubWindowAction Open_window( :SubWindowController ) Last_Window().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 ) ) } resize(400,400) } 12.7 RingLibCurl The LibCurl library is used starting from Ring 1.0 for the Download() and SendEmail() functions implementation. In Ring 1.2 more functions are added to provide a powerful library (RingLibCurl) around LibCurl. Example: load "libcurl.ring" curl = curl_easy_init() cPostThis = "page=4&Number1=4&Number2=5" curl_easy_setopt(curl, CURLOPT_URL, "http://localhost/ringapp/index.ring?page=3") curl_easy_setopt(curl, CURLOPT_POSTFIELDS, cPostThis) 12.7. RingLibCurl 172
  • 206.
    Ring Documentation, Release1.10 curl_easy_perform(curl) curl_easy_cleanup(curl) 12.8 Better Call Command The Call command is updated to support calling functions from object attributes also (not only variables). For example the next code from the Stars Fighter Game cFunc = oself.keypress call cFunc(oGame,oSelf,Key_Space) Can be written in one line call oself.keypress(oGame,oSelf,Key_Space) 12.9 Using NULL instead of NULLPointer() We can pass NULL to functions instead of using NULLPointer() For example the next code from RingLibSDL SDL_RenderCopy(SDL_ren,tex,NULLPointer(),rect) Can be written as in the next line SDL_RenderCopy(SDL_ren,tex,NULL,rect) 12.10 Display Warnings Option In Ring 1.2 the Ring compiler is updated to include the Display Warnings option (-w) Example: load "stdlib.ring" load "stdlib.ring" compiling the program using the Display Warnings option will display the file duplication warning, While without that option the error will pass silent. This is a warning (not an error) because in large projects you may use the same file more than one time. For example it’s common to start each file with the next code. where the function IsMainSourceFile() is part from the stdlib.ring load "stdlib.ring" if IsMainSourceFile() // Testing ok 12.8. Better Call Command 173
  • 207.
    Ring Documentation, Release1.10 12.11 Better Quality Ring 1.2 is more stable, We discovered and fixed more bugs during Ring usage everyday in practical projects. Some functions are optimized to be faster like the SubStr() function. Also the documentation is more better. 12.11. Better Quality 174
  • 208.
    CHAPTER THIRTEEN WHAT IS NEWIN RING 1.1? In this chapter we will learn about the changes and new features in Ring 1.1 release. 13.1 List of changes and new features Ring 1.1 comes with many new features • Better Natural Language Programming Support • Generate/Execute Ring Object Files (*.ringo) • Syntax Flexibility and different styles for I/O and Control Structures • New Functions and Changes • StdLib functions and classes written in Ring • RingLibSDL • Demo Project - Game Engine for 2D Games • RingSQLite • Better Code Generator for Extensions • Using Self.Attribute in the Class Region to define new attributes • Using This.Attribute in nested Braces inside the Class Methods • Better Documentation 13.2 Better Natural Language Programming Support Ring is an innovative language because of it’s compact syntax, smart implementation (small, transparent & visual) and it’s ability to create declarative and natural domain specific languages in a fraction of time. This release add support for calling methods when an expression is evaluated check this example: # Natural Code new program { Accept 2 numbers then print the sum } # Natural Code Implementation 175
  • 209.
    Ring Documentation, Release1.10 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 for more information see the “Natural Language Programming” chapter. 13.3 Generate/Execute Ring Object Files (*.ringo) This feature enable you to distribute your applications without distributing the source code. Also it makes application distribution a simple process where you get one Ring object file for the complete project (many source code files). Also using Ring object file remove the loading time required for compiling the application. Check the “command line options” chapter to know more about this feature. 13.4 Syntax Flexibility and different styles for I/O and Control Struc- tures Programmers are sensitive to the programming language syntax. Great programmers know how to work using many different styles but each programmer may have his/her favorite style. Each programming language comes with a style that you may like or not. Ring is just one of these languages, but as a response to many programmers asking for a better syntax we decided to provide more options. Also some of these features are very necessary for Natural Language Programming. Example : We have two commands to change language keywords and operators. ChangeRingOperator + plus ChangeRingKeyword see print Print 5 plus 5 13.3. Generate/Execute Ring Object Files (*.ringo) 176
  • 210.
    Ring Documentation, Release1.10 ChangeRingOperator plus + ChangeRingKeyword print see We have new styles (Optional) for Input/Output. Example : Put "What is your name? " Get cName Put "Hello " + cName Example : Load "stdlib.ring" Print("What is your name? ") # print message on screen cName=GetString() # get input from the user print("Hello #{cName}") # say hello! We have new styles (optional) for control structures. 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 Put "bad option..." + nl End End Example : Load "stdlib.ring" While True { print(" Main Menu --------- (1) Say Hello (2) About (3) Exit 13.4. Syntax Flexibility and different styles for I/O and Control Structures 177
  • 211.
    Ring Documentation, Release1.10 ") 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") } } Check the next chapters:- • Getting Started - Second Style • Getting Started - Third Style • Control Structures - Second Style - May looks like Lua and Ruby • Control Structures - Third Style - May looks like C (uses braces) • Syntax Flexibility Note: All of these styles are provided automatically by the compiler at the same time, It’s better to select one style for the same project (you can create your style as a mix from these styles) for example you can use Put/Get and Braces. 13.5 New Functions and Changes Changed: • get() function : changed to sysget() • sort() function : can now work on list of objects • find() function : can now work on list of objects Added: • clockspersecond() • CurrentDir() • ExeFileName() • ChDir() • ExeFolder() • varptr() • space() • nullpointer() 13.5. New Functions and Changes 178
  • 212.
    Ring Documentation, Release1.10 • object2pointer() • pointer2object() Check the next chapters • System Functions • Object Oriented Programming (OOP) • Low Level Functions 13.6 StdLib functions and classes written in Ring Ring 1.1 comes with a library called StdLib, it’s written in Ring by the help of Ring Team The library provide a useful group of new functions and classes Example: Load "stdlib.ring" Puts("Test Times()") Times ( 3 , func { see "Hello, World!" + nl } ) Example: Load "stdlib.ring" Puts("Test Map()") See Map( 1:10, func x { return x*x } ) Example: Load "stdlib.ring" Puts("Test Filter()") See Filter( 1:10 , func x { if x <= 5 return true else return false ok } ) 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() oString.right(6).println() Example: Load "stdlib.ring" oList = new list ( [1,2,3] ) oList.Add(4) oList.print() Example: 13.6. StdLib functions and classes written in Ring 179
  • 213.
    Ring Documentation, Release1.10 Load "stdlib.ring" oStack = new Stack oStack.push(1) oStack.push(2) oStack.push(3) see oStack.pop() + nl Example: Load "stdlib.ring" oQueue = new Queue oQueue.add(1) oQueue.add(2) oQueue.add(3) see oQueue.remove() + nl 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() } 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") 13.6. StdLib functions and classes written in Ring 180
  • 214.
    Ring Documentation, Release1.10 } } oTree.children[2].children[3].children[3].set("2.3.3") } see copy("*",60) + nl oTree.print() Check the next chapters: • StdLib Functions • StdLib Classes 13.7 RingLibSDL Ring 1.0 provided RingAllegro to be able to create games using the Allegro game programming library Now Ring 1.1 provide RingLibSDL also so we can have the choice between Allegro or LibSDL Example: Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN) SDL_Delay(2000) SDL_DestroyWindow(win) SDL_Quit() See the RingLibSDL Chapter. 13.8 Demo Project - Game Engine for 2D Games In practice we would create a game engine in a language like C/C++ to get the best performance then provide Ring classes to use the engine. But many 2D Games are simple and creating a game engine in Ring will be fast enough in many cases Also this would be a good demo project to learn about the language concepts where we build things using Object Ori- ented Programming (OOP) then access the power that we have using declarative programming using nested structures or using natural programming. In this project we selected the first way (declarative programming using nested structures) 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" text { x = 10 y=50 animate = false size = 20 13.7. RingLibSDL 181
  • 215.
    Ring Documentation, Release1.10 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 See the “Demo Project - Game Engine for 2D Games” chapter. 13.9 RingSQLite Ring 1.0 provided support for ODBC to use any database and provided native support for MySQL. Now Ring 1.1 provide native support for SQLite database too. Example: 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 ); " + "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 );" sqlite_execute(oSQLite,sql) aResult = sqlite_execute(oSQLite,"select * from COMPANY") 13.9. RingSQLite 182
  • 216.
    Ring Documentation, Release1.10 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 sqlite_close(oSQLite) 13.10 Better Code Generator for Extensions We are using the code generator (written in Ring) every day to add new libraries to Ring. The generator is used to create RingQt and RingAllegro Also in Ring 1.1 it’s used to create RingLibSDL. more features are added like • Set/Get structure members (numbers & pointers) • Using constants • Better Generated Code See the Code Generator chapter. 13.11 Using Self.Attribute in the Class Region to define new at- tributes We can use Self.Attribute in the Class Region (after the class name and before any methods) to define new attributes. class Person name # Define name as attribute if it's not a global variable address phone class person2 self.name # Must Define the attribute self.address self.phone 13.12 Using This.Attribute in nested Braces inside the Class Methods We can use nested braces {} while we are inside methods to access another objects, In this case the current object scope will be changed while we are inside the brace and Self will point to the object that we access using braces {}. In this case we can use This.Attribute and This.Method() to access the object that will be created from the current class. Check the Object Oriented Programming chapter for more information. Also Check the Weight History Application in GUI Development using RingQt chapter. 13.10. Better Code Generator for Extensions 183
  • 217.
    Ring Documentation, Release1.10 13.13 Better Documentation Ring 1.1 documentation (800 pages) is better than Ring 1.0 documentation (340 pages) Many chapters are added for providing better information about the language like • Language Reference • Scope Rules • FAQ And more! 13.13. Better Documentation 184
  • 218.
    CHAPTER FOURTEEN BUILDING FROM SOURCECODE The Ring programming language is a free open source product (MIT License). You can build Ring using CMake or using Scripts (Batch Files or Shell Scripts). The next steps explains building using scripts. 14.1 Building using Microsoft Windows Get the source code git clone http://github.com/ring-lang/ring.git Build Ring (Compiler/VM) cd ring/src buildvc.bat buildvcw.bat Build Ring2EXE cd ../ring2exe buildring2exe.bat Generate RingConsoleColors Source Code and Build cd ../extensions/ringconsolecolors gencode.bat buildvc.bat Build RingInternet cd ../extensions/ringinternet buildvc.bat Generate RingLibCurl Source Code and Build cd ../extensions/ringcurl gencode.bat buildvc.bat Build RingPM cd ../ringpm buildringpm.bat 185
  • 219.
    Ring Documentation, Release1.10 Build RingODBC cd ../extensions/ringodbc buildvc.bat Build RingMySQL cd ../extensions/ringmysql buildvc.bat Build RingSQLite cd ../extensions/ringsqlite buildvc.bat Build RingPostgreSQL cd ../extensions/ringpostgresql gencode.bat buildvc.bat Build RingOpenSSL cd ../extensions/ringopenssl buildvc.bat Build RingMurmurHash cd ../extensions/ringmurmurhash buildvc.bat Generate RingAllegro Source Code and Build cd ../extensions/ringallegro gencode.bat buildvc.bat Generate RingZip Source Code and Build cd ../extensions/ringzip gencode.bat buildvc.bat Generate RingLibuv Source Code and Build cd ../extensions/ringlibuv gencode.bat buildvc.bat Generate RingFreeGLUT Source Code and Build cd ../extensions/ringfreeglut gencode.bat buildvc.bat Generate RingOpenGL Source Code and Build The ringopengl folder contains many sub folders for different OpenGL versions Starting from OpenGL 1.1 to OpenGL 4.6 cd ../extensions/ringopengl/opengl21 gencode.bat buildvc.bat 14.1. Building using Microsoft Windows 186
  • 220.
    Ring Documentation, Release1.10 Generate RingPostgreSQL Source Code and Build cd ../extensions/ringpostgresql gencode.bat buildvc.bat Install Qt 5.5 : https://download.qt.io/archive/qt/5.5/5.5.1/ Generate RingQt Source Code and Build cd ../extensions/ringqt gencode.bat buildmingw32.bat To be able to call ring from any folder cd ../../bin install.bat Add Ring/bin to System path Hit "windows key". Type "Edit the System environment variables" Select "Advanced" tab. Click on "Enviroment Variables..." Double click on "Path" Add at the end the new path separated by semicolon. ;C:RingBin Run Ring Notepad cd applications/rnote ring rnote.ring 14.2 Building using Ubuntu Linux Get the source code git clone http://github.com/ring-lang/ring.git Install Libraries cd ring/src ./installdep.sh Build Ring (Compiler/VM) sudo ./buildgcc.sh Build Ring2EXE cd ../ring2exe sudo ./buildring2exe.sh Generate RingConsoleColors Source Code and Build cd ../extensions/ringconsolecolors ./gencode.sh ./buildgcc.sh 14.2. Building using Ubuntu Linux 187
  • 221.
    Ring Documentation, Release1.10 Build RingInternet cd ../extensions/ringinternet ./buildgcc.sh Generate RingLibCurl Source Code and Build cd ../extensions/ringcurl ./gencode.sh ./buildgcc.sh Build RingPM cd ../ringpm sudo ./buildringpm.sh Build RingODBC cd ../extensions/ringodbc ./buildgcc.sh Build RingMySQL cd ../extensions/ringmysql ./buildgcc.sh Build RingSQLite cd ../extensions/ringsqlite ./buildgcc.sh Build RingPostgreSQL cd ../extensions/ringpostgresql gencode.sh buildgcc.sh Build RingOpenSSL cd ../extensions/ringopenssl ./buildgcc.sh Build RingMurmurHash cd ../extensions/ringmurmurhash ./buildgcc.sh Generate RingAllegro Source Code and Build cd ../extensions/ringallegro ./gencode.sh ./buildgcc.sh Generate RingZip Source Code and Build cd ../extensions/ringzip ./gencode.sh ./buildgcc.sh Generate RingLibuv Source Code and Build We will build Libuv first 14.2. Building using Ubuntu Linux 188
  • 222.
    Ring Documentation, Release1.10 cd ../extensions/ringlibuv/libuv sudo apt-get install libtool m4 automake sh autogen.sh ./configure make make check sudo make install Then we will build RingLibuv cd .. ./gencode.sh ./buildgcc.sh Generate RingFreeGLUT Source Code and Build cd ../extensions/ringfreeglut ./gencode.sh ./buildgcc.sh Generate RingOpenGL Source Code and Build The ringopengl folder contains many sub folders for different OpenGL versions Starting from OpenGL 1.1 to OpenGL 4.6 cd ../extensions/ringopengl/opengl21 gencode.sh buildgcc.sh Generate RingPostgreSQL Source Code and Build cd ../extensions/ringpostgresql ./gencode.sh ./buildgcc.sh Generate RingQt Source Code and Build cd ../extensions/ringqt ./gencode.sh ./buildgcc.sh To be able to call ring from any folder cd ../../bin sudo ./install.sh Run Ring Notepad cd applications/rnote ring rnote.ring 14.3 Building using Fedora Linux Get the source code git clone http://github.com/ring-lang/ring.git Install Libraries 14.3. Building using Fedora Linux 189
  • 223.
    Ring Documentation, Release1.10 cd ring/src ./installdepfedora.sh Build Ring (Compiler/VM) sudo ./buildgcc.sh Build Ring2EXE cd ../ring2exe sudo ./buildring2exe.sh Generate RingConsoleColors Source Code and Build cd ../extensions/ringconsolecolors ./gencode.sh ./buildgcc.sh Build RingInternet cd ../extensions/ringinternet ./buildgcc.sh Generate RingLibCurl Source Code and Build cd ../extensions/ringcurl ./gencode.sh ./buildgcc.sh Build RingPM cd ../ringpm sudo ./buildringpm.sh Build RingODBC cd ../extensions/ringodbc ./buildgcc.sh Build RingMySQL cd ../extensions/ringmysql ./buildgccfedora.sh Build RingSQLite cd ../extensions/ringsqlite ./buildgcc.sh Build RingPostgreSQL cd ../extensions/ringpostgresql gencode.sh buildgcc.sh Build RingOpenSSL cd ../extensions/ringopenssl ./buildgcc.sh Build RingMurmurHash 14.3. Building using Fedora Linux 190
  • 224.
    Ring Documentation, Release1.10 cd ../extensions/ringmurmurhash ./buildgcc.sh Generate RingAllegro Source Code and Build cd ../extensions/ringallegro ./gencode.sh ./buildgcc.sh Generate RingZip Source Code and Build cd ../extensions/ringzip ./gencode.sh ./buildgcc.sh Generate RingLibuv Source Code and Build We will build Libuv first cd ../extensions/ringlibuv/libuv sudo dnf install libtool m4 autoconf automake sh autogen.sh ./configure make make check sudo make install Then we will build RingLibuv cd .. ./gencode.sh ./buildgcc.sh Generate RingFreeGLUT Source Code and Build cd ../extensions/ringfreeglut ./gencode.sh ./buildgcc.sh Generate RingOpenGL Source Code and Build The ringopengl folder contains many sub folders for different OpenGL versions Starting from OpenGL 1.1 to OpenGL 4.6 cd ../extensions/ringopengl/opengl21 gencode.sh buildgcc.sh Generate RingPostgreSQL Source Code and Build cd ../extensions/ringpostgresql ./gencode.sh ./buildgcc.sh Generate RingQt Source Code and Build cd ../extensions/ringqt ./gencode.sh ./buildgccfedora.sh To be able to call ring from any folder 14.3. Building using Fedora Linux 191
  • 225.
    Ring Documentation, Release1.10 cd ../../bin sudo ./install.sh Run Ring Notepad cd applications/rnote ring rnote.ring 14.4 Building using MacOS X Get the source code git clone http://github.com/ring-lang/ring.git Install homebrew (follow the directions on homebrew’s homepage). Install Libraries cd ring/src ./installdepmac.sh Build Ring (Compiler/VM) ./buildclang.sh Build Ring2EXE cd ../ring2exe sudo ./buildring2exe.sh Generate RingConsoleColors Source Code and Build cd ../extensions/ringconsolecolors ./gencode.sh ./buildclang.sh Build RingInternet cd ../extensions/ringinternet ./buildclang.sh Generate RingLibCurl Source Code and Build cd ../extensions/ringcurl ./gencode.sh ./buildclang.sh Build RingPM cd ../ringpm sudo ./buildringpm.sh Build RingODBC cd ../extensions/ringodbc ./buildclang.sh Build RingMySQL cd ../extensions/ringmysql ./buildclang.sh 14.4. Building using MacOS X 192
  • 226.
    Ring Documentation, Release1.10 Build RingSQLite cd ../extensions/ringsqlite ./buildclang.sh Build RingPostgreSQL cd ../extensions/ringpostgresql gencode.sh buildclang.sh Build RingOpenSSL cd ../extensions/ringopenssl ./buildclang.sh Build RingMurmurHash cd ../extensions/ringmurmurhash ./buildclang.sh Generate RingAllegro Source Code and Build cd ../extensions/ringallegro ./gencode.sh ./buildclang.sh Generate RingZip Source Code and Build cd ../extensions/ringzip ./gencode.sh ./buildclang.sh Generate RingLibuv Source Code and Build cd ../extensions/ringlibuv ./gencode.sh ./buildclang.sh Generate RingFreeGLUT Source Code and Build cd ../extensions/ringfreeglut ./gencode.sh ./buildclang.sh Generate RingOpenGL Source Code and Build The ringopengl folder contains many sub folders for different OpenGL versions Starting from OpenGL 1.1 to OpenGL 4.6 cd ../extensions/ringopengl/opengl21 ./gencode.sh ./buildclang.sh Generate RingPostgreSQL Source Code and Build cd ../extensions/ringpostgresql ./gencode.sh ./buildclang.sh Generate RingQt Source Code and Build 14.4. Building using MacOS X 193
  • 227.
    Ring Documentation, Release1.10 cd ../extensions/ringqt ./gencodemac.sh ./buildclang.sh To be able to call ring from any folder cd ../../bin sudo ./install.sh Run Ring Notepad cd applications/rnote sudo ring rnote.ring 14.5 Building using CMake Install libraries (MySQL Client, OpenSSL, LibCurl, Allegro 5 and Qt 5.5) cmake . make 14.5. Building using CMake 194
  • 228.
    CHAPTER FIFTEEN HOW TO CONTRIBUTE? Ringis a free-open source project, Everyone is welcome to contribute to Ring. Project Home : https://github.com/ring-lang/ring You can help in many parts in the project • Documentation • Testing • Samples • Applications • Editors Support • Libraries in Ring • Extensions in C/C++ • Compiler and Virtual Machine (VM) • Ideas and suggestions 15.1 Special thanks to contributors Throughout the creation of this project, Ring relied heavily on contributions from experts along with college students. Their input was invaluable, and we want to take a moment to thank them and recognize them for all of their hard work. Ring Team: http://ring-lang.sf.net/team.html 15.2 Documentation You can modify anything in the documentation, by updating the text files (*.txt) in this folder : https://github.com/ring- lang/ring/tree/master/docs/source The documentation is created using Sphinx : http://www.sphinx-doc.org/en/stable/ 15.3 Testing You can write new tests in this folder https://github.com/ring-lang/ring/tree/master/tests/scripts 195
  • 229.
    Ring Documentation, Release1.10 15.4 Samples You can add new samples to this folder https://github.com/ring-lang/ring/tree/master/samples/other 15.5 Applications You can add new applications to this folder https://github.com/ring-lang/ring/tree/master/applications 15.6 Editors Support You can help in supporting Ring in different code editors Check the next folder https://github.com/ring-lang/ring/tree/master/editor 15.7 Libraries in Ring You can update and add libraries to this folder https://github.com/ring-lang/ring/tree/master/ringlibs 15.8 Extensions in C/C++ You can add and update extensions in this folder https://github.com/ring-lang/ring/tree/master/extensions 15.9 Compiler and Virtual Machine (VM) • Source Code (C Language) : https://github.com/ring-lang/ring/tree/master/src • Visual Source (PWCT) : https://github.com/ring-lang/ring/tree/master/visualsrc 15.10 Ideas and suggestions You can share your ideas, suggestions and questions in this group https://groups.google.com/forum/#!forum/ring-lang 15.4. Samples 196
  • 230.
    CHAPTER SIXTEEN GETTING STARTED -FIRST STYLE 16.1 Hello World The next program prints the Hello World message on the screen (std-out). see "Hello World" 16.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 16.3 Create Executable File Using Ring2EXE we can create executable file for our application ring2exe hello.ring -static 16.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" 16.5 Multi-Line literals Using Ring we can write multi-line literal, see the next example 197
  • 231.
    Ring Documentation, Release1.10 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?" 16.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 16.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 16.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: Hello, World! 1 2 3 4 5 6 7 8 16.6. Getting Input 198
  • 232.
    Ring Documentation, Release1.10 9 10 16.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. 16.9. Writing Comments 199
  • 233.
    CHAPTER SEVENTEEN GETTING STARTED -SECOND STYLE 17.1 Hello World The next program prints the Hello World message on the screen (std-out). put "Hello World" 17.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 17.3 Create Executable File Using Ring2EXE we can create executable file for our application ring2exe hello.ring -static 17.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" 17.5 Multi-Line literals Using Ring we can write multi-line literal, see the next example 200
  • 234.
    Ring Documentation, Release1.10 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?" 17.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 17.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 17.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 */ 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. 17.6. Getting Input 201
  • 235.
    CHAPTER EIGHTEEN GETTING STARTED -THIRD STYLE 18.1 Hello World The next program prints the Hello World message on the screen (std-out). load "stdlib.ring" print("Hello World") 18.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 18.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 ring2exe hello.ring -dist -allruntime -noqt -noallegro 202
  • 236.
    Ring Documentation, Release1.10 18.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") 18.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?") 18.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}") 18.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}") 18.8 Writing Comments We can write one line comments and multi-line comments 18.4. Not Case-Sensitive 203
  • 237.
    Ring Documentation, Release1.10 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. 18.8. Writing Comments 204
  • 238.
    CHAPTER NINETEEN 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. 19.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 205
  • 239.
    Ring Documentation, Release1.10 19.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 19.2. Creating and running your first Console Application 206
  • 240.
    Ring Documentation, Release1.10 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. 19.2. Creating and running your first Console Application 207
  • 241.
    Ring Documentation, Release1.10 19.3 Creating and running your first GUI/Mobile Application To learn how to create GUI applications using Ring check the “Desktop 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. 19.3. Creating and running your first GUI/Mobile Application 208
  • 242.
    Ring Documentation, Release1.10 The next screen shot present the application during the runtime 19.4 Creating and running your first Web Application To learn how support Ring in your web server and how to create web applications using Ring check the “Web Devel- opment (CGI Library)” chapter. Note: You need to support the Ring language in your web server to be able to run the next example. 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. 19.4. Creating and running your first Web Application 209
  • 243.
    Ring Documentation, Release1.10 For Windows users, Ring comes with Apache Web server! We can run any web application from any folder directly without doing any configuration. 19.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: 19.5. Creating and running your first Desktop/Mobile Game 210
  • 244.
    Ring Documentation, Release1.10 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. 19.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 19.6. The Main File in the Project 211
  • 245.
    Ring Documentation, Release1.10 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: 19.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” 19.7. The File Menu 212
  • 246.
    Ring Documentation, Release1.10 19.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. 19.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) 19.8. The Edit Menu 213
  • 247.
    Ring Documentation, Release1.10 Also we can quickly show/hide group of dockable windows based on the context 19.9. The View Menu 214
  • 248.
    Ring Documentation, Release1.10 19.10 The Program Menu From this menu we can run the programs Also we can set the Main file in the project 19.11 The Browser Menu From this menu we can quickly open common links in the browser 19.10. The Program Menu 215
  • 249.
    Ring Documentation, Release1.10 19.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 19.13 The Distribute Menu From this menu we can build an executable file for the application Also we can prepare the application for distribution 19.12. The Tools Menu 216
  • 250.
    Ring Documentation, Release1.10 19.14 The Help Menu From this menu we can get the help files (CHM & PDF) 19.14. The Help Menu 217
  • 251.
    CHAPTER TWENTY USING OTHER CODEEDITORS In the Ring/Editor folder you will find extensions for the next editors • Notepad++ • Geany • Atom • Sublime Text 2 • Visual Studio IDE • Emacs • Visual Studio Code (VSCode) 20.1 Using Notepad++ Folder : ring/editor/notepad_plus_plus • Open Notepad++ • Open the “Language” menu • Select “Define your language...” • Click “Import...” • select Ring.xml • Select “OK” on the “Import successful” dialog and close the “User Defined Language” dialog/panel • You may need to restart notepad++ 218
  • 252.
    Ring Documentation, Release1.10 20.2 Using Geany Folder : ring/editor/geany • Run Geany editor • Click on “Tools -> configuration files -> filetypes_extensions.conf” menu • Add this line “Ring=*.ring;” without quotes after [Extensions] • In unbuntu copy file “filetypes.Ring.conf” to folder “/home/USERNAME/filetypes.Ring.conf” • You can run your files by pressing F5 button 20.2. Using Geany 219
  • 253.
    Ring Documentation, Release1.10 20.3 Using Atom Folder : ring/editor/atom Just Copy the folder atom-language-ring to the next path "C:Users{UserName}.atomPackages" 20.3. Using Atom 220
  • 254.
    Ring Documentation, Release1.10 20.4 Using Sublime Text 2 Folder : ring/editor/sublime text 2 In the folder Sublime_Text_2 you will find the next three files 1 - ring.json-tmlanguage 2 - ring.sublime-build 3 - ring.tmlanguage Just Copy the files to the next path "C:Users{UserName}AppDataRoamingSublime Text 2PackagesUser" The file ring.sublime-build includes the next line "cmd": ["B:ringbinring.exe","$file"], You can modify it according to the ring.exe path in your machine 20.4. Using Sublime Text 2 221
  • 255.
    Ring Documentation, Release1.10 20.5 Using Visual Studio IDE Folder : ring/editor/visualstudio Check the ReadMe file for installation instructions. 20.5. Using Visual Studio IDE 222
  • 256.
    Ring Documentation, Release1.10 20.6 Using Emacs Editor Folder : ring/editor/emacs Check the ReadMe file for installation instructions. Screen Shot: 20.7 Visual Studio Code Folder : ring/vscode Check the ReadMe file for installation instructions. Screen Shot: 20.6. Using Emacs Editor 223
  • 257.
    Ring Documentation, Release1.10 20.7. Visual Studio Code 224
  • 258.
    CHAPTER TWENTYONE 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). 21.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 21.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 225
  • 259.
    Ring Documentation, Release1.10 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 21.3 Weakly Typed Ring is a weakly typed language, this means that the language can automatically convert between data types (like string & numbers) when that conversion make sense. 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 21.3. Weakly Typed 226
  • 260.
    CHAPTER TWENTYTWO OPERATORS In this chapterwe will introduce the operators provided by the Ring programming langauge. 22.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 22.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 22.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 227
  • 261.
    Ring Documentation, Release1.10 Another style Operator Description Example Result && Logical AND x && y False || Logical OR x || y True ! Logical Not ! x False 22.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 22.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 22.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 22.4. Bitwise Operators 228
  • 262.
    Ring Documentation, Release1.10 22.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 22.7. Operators Precedence 229
  • 263.
    CHAPTER TWENTYTHREE CONTROL STRUCTURES -FIRST STYLE In this chapter we are going to learn about the control structures provided by the Ring programming language. 23.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 230
  • 264.
    Ring Documentation, Release1.10 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 23.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 Syntax: 23.2. Looping 231
  • 265.
    Ring Documentation, Release1.10 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 23.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 23.3. Using The Step option with For in 232
  • 266.
    Ring Documentation, Release1.10 23.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 23.5 Do Again Loop Syntax: do Block of statements again expression Example: x = 1 do see x + nl x++ again x <= 10 23.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 23.4. Using For in to modify lists 233
  • 267.
    Ring Documentation, Release1.10 23.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 23.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 23.9 Exit/Loop inside sub functions While we are inside a loop, we can call a function then use the exit and/or loop command inside that function and the command will work on the outer loop. Example: # print numbers from 1 to 10 except number 5. for x = 1 to 10 ignore(x,5) see x + nl next func ignore x,y if x = y loop ok 23.7. Exit from two loops 234
  • 268.
    Ring Documentation, Release1.10 23.10 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 23.11 Comments about evaluation • True, False, nl & NULL are variables defined by the language • True = 1 23.10. Short-circuit evaluation 235
  • 269.
    Ring Documentation, Release1.10 • 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 23.11. Comments about evaluation 236
  • 270.
    CHAPTER TWENTYFOUR 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. 24.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 Block of statements end 237
  • 271.
    Ring Documentation, Release1.10 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 24.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 Put "bad option..." + nl End End • For Loop Syntax: 24.2. Looping 238
  • 272.
    Ring Documentation, Release1.10 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 24.3 Exceptions try Block of statements catch Block of statements end 24.3. Exceptions 239
  • 273.
    CHAPTER TWENTYFIVE 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. 25.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") } 240
  • 274.
    Ring Documentation, Release1.10 • 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") } 25.2 Looping • While Loop Syntax: while Expression { Block of statements } Example: Load "stdlib.ring" While True { print(" Main Menu --------- 25.2. Looping 241
  • 275.
    Ring Documentation, Release1.10 (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" # print even numbers from 0 to 10 for x = 0 to 10 step 2 { print("#{x}n") } 25.2. Looping 242
  • 276.
    Ring Documentation, Release1.10 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" } } print(aList) # print the list items 25.3 Exceptions 25.3. Exceptions 243
  • 277.
    Ring Documentation, Release1.10 try { Block of statements catch Block of statements } 25.3. Exceptions 244
  • 278.
    CHAPTER TWENTYSIX GETTING INPUT We canget input from the keyboard using • The Give Command • The GetChar() Function • The Input() Function 26.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 26.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 (2) Exit " Option = GetChar() 245
  • 279.
    Ring Documentation, Release1.10 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 26.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 26.3. Input() Function 246
  • 280.
    CHAPTER TWENTYSEVEN 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 27.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 27.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: 247
  • 281.
    Ring Documentation, Release1.10 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 27.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 27.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 27.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: 27.3. Declare parameters 248
  • 282.
    Ring Documentation, Release1.10 # 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 27.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. 27.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: 27.6. Variables Scope 249
  • 283.
    Ring Documentation, Release1.10 if novalue() = NULL See "the function doesn't return a value" + nl ok func novalue 27.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 27.8. Recursion 250
  • 284.
    CHAPTER TWENTYEIGHT 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 28.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 28.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: 251
  • 285.
    Ring Documentation, Release1.10 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 28.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 28.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 28.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: 28.3. Declare parameters 252
  • 286.
    Ring Documentation, Release1.10 # 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 28.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. 28.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: 28.6. Variables Scope 253
  • 287.
    Ring Documentation, Release1.10 if novalue() = NULL put "the function doesn't return a value" + nl end def novalue 28.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 28.8. Recursion 254
  • 288.
    CHAPTER TWENTYNINE 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 29.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") } 29.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: 255
  • 289.
    Ring Documentation, Release1.10 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") } 29.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) } 29.4 Send Parameters To send parameters to function, type the parameters inside () after the function name Syntax: funcname(parameters) Example: /* output ** 8 ** 3000 */ load "stdlib.ring" sum(3,5) sum(1000,2000) func sum(x,y) { print(x+y) } 29.3. Declare parameters 256
  • 290.
    Ring Documentation, Release1.10 29.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") } 29.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 { 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. 29.7 Return Value The function can return a value using the Return command. Syntax: 29.5. Main Function 257
  • 291.
    Ring Documentation, Release1.10 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 { } 29.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) } } 29.8. Recursion 258
  • 292.
    CHAPTER THIRTY PROGRAM STRUCTURE In thischapter we will learn about using many source code files in the same project. 30.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. 30.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") # File : sub.ring func sayhello cName see "Hello " + cName + nl 259
  • 293.
    Ring Documentation, Release1.10 30.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 30.3. Load Package 260
  • 294.
    CHAPTER THIRTYONE LISTS In this chapterwe are going to learn how to deal with lists. 31.1 Create Lists We can create new lists by defining the list items inside square bracts. 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) Example aList = list(10) # aList contains 10 items Note: the list index start from 1 31.2 Add Items To add new items to the list, we can use the Add() function. Syntax: Add(List,Item) 261
  • 295.
    Ring Documentation, Release1.10 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 31.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 31.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 31.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 31.3. Get List Size 262
  • 296.
    Ring Documentation, Release1.10 31.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 31.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: 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 31.6. Set List Item 263
  • 297.
    Ring Documentation, Release1.10 31.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 Output: ahmed 14000 ibrahim 11000 mahmoud 15000 mohammed 12000 samir 16000 31.9 Reverse We can reverse a list using the reverse() function. Syntax: 31.8. Sort 264
  • 298.
    Ring Documentation, Release1.10 Reverse(List) ---> Reversed List Example: aList = [10,20,30,40,50] aList = reverse(aList) see aList # print 50 40 30 20 10 31.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 31.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 31.12 Copy Lists We can copy lists (including nested lists) using the Assignment operator. Example: 31.10. Insert Items 265
  • 299.
    Ring Documentation, Release1.10 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 31.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 nMax = len(list) for x = 1 to nMax list + list[x] next return list func mylist return [10,20,30,40,50] 31.14 Using Lists during definition We can use 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 31.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 31.13. First-class lists 266
  • 300.
    Ring Documentation, Release1.10 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] 31.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 31.17 Passing Parameters or Argumnents 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: 31.16. Access List Items by String Index 267
  • 301.
    Ring Documentation, Release1.10 myconnect ( [ :server = "myserver.com" , :port = 80 , :username = "mahmoud" , :password = "password" ] ) func myconnect mypara # print connection details see "User Name : " + mypara[:username] + nl + "Password : " + mypara[:password] + nl + "Server : " + mypara[:server] + nl + "Port : " + mypara[:port] 31.18 Passing Parameters or Argumnents Using List Array Passing Arguments or Parmameters 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 31.19 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 31.18. Passing Parameters or Argumnents Using List Array 268
  • 302.
    Ring Documentation, Release1.10 next ###----------------------------------------------- ### 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 dimesions: 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 31.20 Swap Items We can swap the list items using the Swap() function. Example: aList = [:one,:two,:four,:three] see aList 31.20. Swap Items 269
  • 303.
    Ring Documentation, Release1.10 see copy("*",50) + nl swap(aList,3,4) see aList Output one two four three ************************************************** one two three four 31.20. Swap Items 270
  • 304.
    CHAPTER THIRTYTWO STRINGS In this chapterwe are going to learn about strings creation and manipulation. 32.1 String Literals Syntax: cStr = "This is a string" cStr2 = 'Another string' cStr3 = :JustAnotherString cStr4 = `Yet "another" 'string' ! ` 32.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 32.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) 271
  • 305.
    Ring Documentation, Release1.10 32.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 32.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 32.6 Right() Function We can get a specified number of characters from a string using the Right() function. 32.4. Access String Letters 272
  • 306.
    Ring Documentation, Release1.10 The starting position is the last character on the right. Syntax: Right(string,count) Example: see Right("Hello World!",6) # print World! 32.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 32.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*** 32.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: cStr = "Hello How are you? are you fine?" see lines(cStr) # print 3 32.7. Trim() Function 273
  • 307.
    Ring Documentation, Release1.10 32.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 32.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 32.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 32.13 Get Number of Characters From Position Syntax: substr(string,position,count) ---> Get characters starting from position Example: cStr = "Welcome to the Ring programming language" nPos = substr(cStr,"Ring") # nPos = 16 see substr(cStr,nPos,4) # print Ring 32.14 Transform Substring To Another Substring Syntax: 32.10. Substr() Function 274
  • 308.
    Ring Documentation, Release1.10 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 32.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 32.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: /* 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 */ 32.15. strcmp() Function 275
  • 309.
    Ring Documentation, Release1.10 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 32.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 ? "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] 32.17. Merge binary characters 276
  • 310.
    Ring Documentation, Release1.10 ? 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 32.17. Merge binary characters 277
  • 311.
    CHAPTER THIRTYTHREE DATE AND TIME Inthis chapter we are going to learn about the date and time functions. 33.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 33.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 33.3 Time() Function We can get the system time using the Time() function. Example: See "Time : " + time() 278
  • 312.
    Ring Documentation, Release1.10 33.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 33.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 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) 33.4. Date() Function 279
  • 313.
    Ring Documentation, Release1.10 ** 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 Example: See "Month Name : " + TimeList()[4] # May 33.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 33.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 33.6. AddDays() Function 280
  • 314.
    Ring Documentation, Release1.10 33.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, "/") arrayTime = split(Time, ":") Year = arrayDate[3] ; Month = arrayDate[2] ; Day = arrayDate[1] Hour = arrayTime[1] ; Minute = arrayTime[2] ; Second = arrayTime[3] cDate1 = Day +"/"+ Month +"/"+ Year cDate2 = "01/01/" + Year DayOfYear = DiffDays( cDate1, cDate2) ### Formula tm_sec = Second * 1 tm_min = Minute * 60 tm_hour = Hour * 3600 tm_yday = DayOfYear * 86400 tm_year = Year - 1900 tm_year1 = ( tm_year - 70) * 31536000 tm_year2 = ( floor(( tm_year - 69) / 4 )) * 86400 tm_year3 = ( floor(( tm_year - 1) / 100 )) * 86400 tm_year4 = ( floor(( tm_year + 299) / 400 )) * 86400 ### Result EpochSec = tm_sec + tm_min + tm_hour + tm_yday + tm_year1 + tm_year2 - tm_year3 + tm_year4 return EpochSec 33.8. EpochTime() Function 281
  • 315.
    CHAPTER THIRTYFOUR 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 34.1 Check Data Type The next functions can be used to check the data type • isstring() • isnumber() • islist() • type() • isnull() 34.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 34.3 IsNumber() Function Using the IsNumber() function we can know if the value is a number or not Syntax: 282
  • 316.
    Ring Documentation, Release1.10 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 34.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 34.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 34.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: 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 34.4. IsList() Function 283
  • 317.
    Ring Documentation, Release1.10 34.7 Check Character The next functions can be used to check character • isalnum() • isalpha() • iscntrl() • isdigit() • isgraph() • islower() • isprint() • ispunct() • isspace() • isupper() • isxdigit() 34.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 34.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 34.7. Check Character 284
  • 318.
    Ring Documentation, Release1.10 34.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 34.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 34.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: see isgraph("abcdef") + nl + # print 1 isgraph("abc def") # print 0 34.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 34.10. IsCntrl() Function 285
  • 319.
    Ring Documentation, Release1.10 34.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 34.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 34.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 34.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 34.14. IsPrint() Function 286
  • 320.
    Ring Documentation, Release1.10 34.18 IsXdigit() Function We can test a character or a string using the IsXdigit() Function Syntax: IsXdigit(value) ---> 1 if the value is a hexdecimal digit character or 0 if not Example: see isxdigit("0123456789abcdef") + nl + # print 1 isxdigit("123z") # print 0 34.19 Conversion The next functions can be used for conversion • number() • string() • ascii() • char() • hex() • dec() • str2hex() • hex2str() 34.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 34.21 String() Function We can convert numbers to strings using the String() function or the + operator. Syntax: String(number) ---> String "" + number ---> String 34.18. IsXdigit() Function 287
  • 321.
    Ring Documentation, Release1.10 Example: see string(5) + 5 + nl # print 55 see "" + 10 + 2 # print 102 34.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 34.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 34.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 34.25 Dec() Function We can convert hexadecimal to decimal using the Dec() function Syntax: Dec(hexadecimal) ---> decimal 34.22. Ascii() Function 288
  • 322.
    Ring Documentation, Release1.10 Example: See dec("a") + nl + # print 10 dec("c8") # print 200 34.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 34.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 34.26. Str2hex() Function 289
  • 323.
    CHAPTER THIRTYFIVE MATHEMATICAL FUNCTIONS In thischapter we are going to learn about the mathematical functions 35.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 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 35.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 290
  • 324.
    Ring Documentation, Release1.10 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 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 35.2. Example 291
  • 325.
    Ring Documentation, Release1.10 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 35.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 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 35.3. Random() Function 292
  • 326.
    Ring Documentation, Release1.10 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 35.4 SRandom() Function The SRandom() function initialize random number generator. Syntax: SRandom(x) 35.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: 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 35.4. SRandom() Function 293
  • 327.
    Ring Documentation, Release1.10 Output: 3372029979.00 35.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 35.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 35.6. Decimals() Functions 294
  • 328.
    Ring Documentation, Release1.10 35.8 Using f after numbers We can use the ‘f’ letter after numbers. Example: x = 19.99f see type(x) + nl Output: NUMBER 35.8. Using f after numbers 295
  • 329.
    CHAPTER THIRTYSIX FILES In this chapterwe are going to learn about files functions. • Read() • Write() • Dir() • Rename() • Remove() • fopen() • fclose() • fflush() • freopen() • tempfile() • tempname() • fseek() • ftell() • rewind() • fgetpos() • fsetpos() • clearerr() • feof() • ferror() • perror() • fgetc() • fgets() • fputc() • fputs() • ungetc() • fread() 296
  • 330.
    Ring Documentation, Release1.10 • fwrite() • fexists() • Numbers and Bytes 36.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") 36.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) 36.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 • Type (0 = File , 1 = Folder/Directory) Example: 36.1. Read() Function 297
  • 331.
    Ring Documentation, Release1.10 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) 36.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") 36.5 Remove() Function We can delete a file using the Remove() function Syntax: Remove(cFileName) Example: remove("test.txt") 36.6 Fopen() Function We can open a file using the Fopen() function Syntax: Fopen(cFileName,cMode) ---> File Handle 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 36.4. Rename() Function 298
  • 332.
    Ring Documentation, Release1.10 36.7 Fclose() Function When we open a file using fopen() function, we can close it using the Fclose() function Syntax: Fclose(file handle) 36.8 Fflush() Function We can flushes the output buffer of a stream using the Fflush() function Syntax: Fflush(file handle) 36.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: # Output to stdout Done # Output to file : myprogoutput.txt welcome 1 2 3 4 5 6 7 36.7. Fclose() Function 299
  • 333.
    Ring Documentation, Release1.10 8 9 10 36.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 36.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 36.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 36.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 36.10. Tempfile() Function 300
  • 334.
    Ring Documentation, Release1.10 36.14 Rewind() Function We can set the file position to the beginning of the file using the Rewind() function Syntax: Rewind(file handle) 36.15 Fgetpos() Function We can get handle to the current file position using the Fgetpos() function Syntax: Fgetpos(file handle) ---> position handle 36.16 Fsetpos() Function We can set the current file position using the Fgetpos() function Syntax: Fsetpos(file handle,position handle) 36.17 Clearerr() Function We can clear the EOF error and the error indicators of a stream using the clearerr() function Syntax: Clearerr(file handle) 36.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 36.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 36.14. Rewind() Function 301
  • 335.
    Ring Documentation, Release1.10 36.20 Perror() Function We can print error message to the stderr using the Perror() function Syntax: Perror(cErrorMessage) 36.21 Fgetc() Function We can get the next character from the stream using the Fgetc() function Syntax: Fgetc(file handle) ---> returns character or EOF 36.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. 36.23 Fputc() Function We can write a character to the stream using the Fputc() function Syntax: Fputc(file handle,cChar) 36.24 Fputs() Function We can write a string to the stream using the Fputs() function Syntax: Fputs(file handle,cString) 36.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: 36.20. Perror() Function 302
  • 336.
    Ring Documentation, Release1.10 Ungetc(file handle,character) 36.26 Fread() Function We can read data from a stream using the Fread() function Syntax: Fread(file handle,nSize) 36.27 Fwrite() Function We can write data to a stream using the Fwrite() function Syntax: Fwrite(file handle,cString) 36.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 36.29 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 36.26. Fread() Function 303
  • 337.
    Ring Documentation, Release1.10 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") 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 36.29. Example 304
  • 338.
    Ring Documentation, Release1.10 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) 36.30 Numbers and Bytes The next functions to convert between Numbers and Bytes. • Int2Bytes() • Float2Bytes() • Double2Bytes() • Bytes2Int() • Bytes2Float() • Bytes2Double() Example: 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 36.30. Numbers and Bytes 305
  • 339.
    CHAPTER THIRTYSEVEN SYSTEM FUNCTIONS In thischapter we are going to learn about the system functions • System() • SysGet() • IsMSDOS() • IsWindows() • IsWindows64() • IsUnix() • IsMacOSX() • IsLinux() • IsFreeBSD() • IsAndroid() • Windowsnl() • Get Command Line Arguments • Get Active Source File Name • CurrentDir() • ExeFileName() • ChDir() • ExeFolder() • Version() • Shutdown() 37.1 System() Function We can execute system commands using the system() function Syntax: System(cCommand) Example: 306
  • 340.
    Ring Documentation, Release1.10 System("myapp.exe") # Run myapp.exe System("ls") # print list of files 37.2 SysGet() Function We can get environment variables using the Get() function Syntax: SysGet(cVariable) Example: see sysget("path") # print system path information 37.3 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 37.4 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 37.5 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 37.6 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 37.2. SysGet() Function 307
  • 341.
    Ring Documentation, Release1.10 37.7 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 37.8 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 37.9 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 37.10 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 37.11 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 37.7. IsMacOSX() Function 308
  • 342.
    Ring Documentation, Release1.10 IsLinux() --> 0 IsFreeBSD() --> 0 IsAndroid() --> 0 37.12 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) 37.13 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 37.12. Windowsnl() Function 309
  • 343.
    Ring Documentation, Release1.10 Size : 4 ring testssyspara.ring 1 10 ============================== 1 2 3 4 5 6 7 8 9 10 37.14 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: 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 37.15 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. 37.14. Get Active Source File Name 310
  • 344.
    Ring Documentation, Release1.10 Func IsMainSourceFile if PrevFileName() = sysargv[2] return true ok return false 37.16 CurrentDir() Function Return the path of the current directory Syntax: CurrenDir() ---> String contains the path of the currect directory 37.17 ExeFileName() Function Return the Ring executable file name Syntax: exefilename() ---> String contains the Ring executable file name 37.18 ChDir() Function Change the current directory Syntax: ChDir(cNewPath) 37.19 ExeFolder() Function Return the Ring executable file path Syntax: exefolder() ---> String contains the Ring executable path 37.20 Version() Function Return the Ring version Syntax: version() ---> String contains the Ring version Output: 37.16. CurrentDir() Function 311
  • 345.
    Ring Documentation, Release1.10 1.10 37.21 Shutdown() Function Close the application Syntax: shutdown(nStatus) ---> Close the application 37.21. Shutdown() Function 312
  • 346.
    CHAPTER THIRTYEIGHT EVAL() AND DEBUGGING Inthis chapter we are going to learn about • Error Handling using Try/Catch/Done • Eval() function • Raise() function • Assert() function 38.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) : Cann't divide by zero ! 38.2 Eval() Function We can execute code during the runtime from string using the Eval() function Syntax: 313
  • 347.
    Ring Documentation, Release1.10 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 38.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: 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 38.3. Raise() Function 314
  • 348.
    Ring Documentation, Release1.10 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 38.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 38.4. Assert() Function 315
  • 349.
    CHAPTER THIRTYNINE DEMO PROGRAMS In thischapter we will see simple demo programs • Language Shell • Main Menu 39.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 316
  • 350.
    Ring Documentation, Release1.10 39.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 39.2. Main Menu 317
  • 351.
    Ring Documentation, Release1.10 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 =========== [1] Say Hello [2] Sum two numbers 39.2. Main Menu 318
  • 352.
    Ring Documentation, Release1.10 [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 39.2. Main Menu 319
  • 353.
    CHAPTER FORTY 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 40.1 odbc_init() Function We can create ODBC Handle using the odbc_init() function Syntax: odbc_init() ---> ODBC Handle 320
  • 354.
    Ring Documentation, Release1.10 40.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 40.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 40.4 odbc_close() Function After the end of using ODBC functions we can free resources using ODBC_Close() function Syntax: odbc_close(ODBC Handle) 40.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 Microsoft Excel-Treiber (*.xls) - SQLLevel=0 Microsoft Access Driver (*.mdb) - SQLLevel=0 Driver do Microsoft Access (*.mdb) - SQLLevel=0 40.2. odbc_drivers() Function 321
  • 355.
    Ring Documentation, Release1.10 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 40.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 Visual FoxPro Database - Microsoft Visual FoxPro Driver Visual FoxPro Tables - Microsoft Visual FoxPro Driver 40.6. Print List of ODBC Data Sources 322
  • 356.
    Ring Documentation, Release1.10 40.7 odbc_connect() Function We can connect to the database using the odbc_connect() function. Syntax: odbc_connect(ODBC Handle, cConnectionString) 40.8 odbc_disconnect() Function We can close the connection to the database using the odbc_disconnect() function. Syntax: odbc_disconnect(ODBC Handle) 40.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... 40.10 odbc_execute() Function We can execute SQL Statements on the database using the odbc_execute() function. Syntax: odbc_execute(ODBC Handle, cSQLStatement) 40.11 odbc_colcount() Function We can get columns count in the query result using the odbc_colcount() function. Syntax: 40.7. odbc_connect() Function 323
  • 357.
    Ring Documentation, Release1.10 odbc_colcount(ODBC Handle) ---> Columns Count as Number 40.12 odbc_fetch() Function We can fetch a row from the query result using the odbc_fetch() function. Syntax: odbc_fetch(ODBC Handle) 40.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 40.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) + " - " next end See "Close database..." + nl odbc_disconnect(pODBC) odbc_close(pODBC) 40.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: 40.12. odbc_fetch() Function 324
  • 358.
    Ring Documentation, Release1.10 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... 40.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: 40.16. odbc_columns() Function 325
  • 359.
    Ring Documentation, Release1.10 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... 40.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 40.18 odbc_commit() Function We can commit updates to the database using the odbc_commit() function. Syntax: odbc_commit(ODBC Handle) 40.19 odbc_rollback() Function We can rollback updates to the database using the odbc_rollback() function. Syntax: odbc_rollback(ODBC Handle) 40.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) 40.17. odbc_autocommit() Function 326
  • 360.
    Ring Documentation, Release1.10 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... 40.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) 40.21. Save and Restore images 327
  • 361.
    Ring Documentation, Release1.10 See "Write image file" + nl write("testsgreat.jpg",hex2str( odbc_getdata(pODBC,3) ) ) ok See "Close database..." + nl odbc_disconnect(pODBC) odbc_close(pODBC) 40.21. Save and Restore images 328
  • 362.
    CHAPTER FORTYONE 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 41.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: see "MySQL Client Version : " + mysql_info() 329
  • 363.
    Ring Documentation, Release1.10 Output: MySQL Client Version : 6.1.5 41.2 MySQL_Init() Function We can start using MySQL Client through the MySQL_Init() function. Syntax: MySQL_Init() ---> MySQL Handle 41.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 41.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 41.5 MySQL_Close() Function We can close the connection to the MySQL database using the MySQL_Close() function Syntax: MySQL_Close(MySQL Handle) 41.6 MySQL_Query() Function We can execute SQL queries using the MySQL_Query() function Syntax: MySQL_Query(MySQL Handle, cSQLQuery) 41.2. MySQL_Init() Function 330
  • 364.
    Ring Documentation, Release1.10 41.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 "Cann'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 41.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 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)") 41.7. Create Database 331
  • 365.
    Ring Documentation, Release1.10 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 41.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 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 41.9. MySQL_Insert_ID() Function 332
  • 366.
    Ring Documentation, Release1.10 41.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 41.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) 41.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) see "close database" + nl mysql_close(con) Output: Connect to database Execute Query Print Result Mahmoud Fayed close database 41.13 MySQL_Columns() Function We can get a list of columns names using the MySQL_Columns() function. Syntax: 41.10. MySQL_Result() Function 333
  • 367.
    Ring Documentation, Release1.10 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 41.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: 41.14. MySQL_Result2() Function 334
  • 368.
    Ring Documentation, Release1.10 Connect to database Execute Query Print Result Id Name Salary 1 Mahmoud 15000 2 Samir 16000 3 Fayed 17000 Close database 41.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 41.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... 41.15. MySQL_Escape_String() Function 335
  • 369.
    Ring Documentation, Release1.10 41.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... 41.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 41.19 MySQL_Commit() Function We can commit updates to the database using the MySQL_Commit() function. Syntax: MySQL_Commit(MySQL Handle) 41.20 MySQL_Rollback() Function We can rollback updates to the database using the MySQL_Rollback() function. Syntax: MySQL_Rollback(MySQL Handle) 41.21 Transaction Example The next example presents the usage of MySQL_Autocommit(), MySQL_Commit() & MySQL_RollBack() functions. Example: 41.17. Restore Image From The Database 336
  • 370.
    Ring Documentation, Release1.10 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)") 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 41.21. Transaction Example 337
  • 371.
    CHAPTER FORTYTWO 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 42.1 sqlite_init() function Syntax: sqlite_init() ---> SQLite Object 42.2 sqlite_open() function Syntax: sqlite_open(SQLite Object,cFileName) 42.3 sqlite_execute() function Syntax: sqlite_execute(SQLite Object,cSQLStatement) 42.4 sqlite_close() function Syntax: sqlite_close(SQLite Object) 338
  • 372.
    Ring Documentation, Release1.10 42.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 Egypt 42.5. Example 339
  • 373.
    Ring Documentation, Release1.10 20000.0 4 Ibrahim 24 Egypt 65000.0 ************************************************** Mahmoud Ahmed Mohammed Ibrahim 42.5. Example 340
  • 374.
    CHAPTER FORTYTHREE POSTGRESQL FUNCTIONS In thischapter we will learn about using the PostgreSQL database in the Ring programming language. 43.1 Loading the library Before using the next function load the postgresqllib.ring library load "postgresqllib.ring" # Use PostgreSQL functions 43.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) next 341
  • 375.
    Ring Documentation, Release1.10 ? 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 res = PQexec(conn, " DROP DATABASE mahdb; 43.2. Examples 342
  • 376.
    Ring Documentation, Release1.10 ") 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 ? PQfname(res, i-1) next ? copy("*",60) 43.2. Examples 343
  • 377.
    Ring Documentation, Release1.10 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 43.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 PGRES_COPY_BOTH PGRES_SINGLE_TUPLE PG_DIAG_SEVERITY PG_DIAG_SQLSTATE PG_DIAG_MESSAGE_PRIMARY PG_DIAG_MESSAGE_DETAIL 43.3. RingPostgreSQL Constants 344
  • 378.
    Ring Documentation, Release1.10 PG_DIAG_MESSAGE_HINT PG_DIAG_STATEMENT_POSITION PG_DIAG_INTERNAL_POSITION PG_DIAG_INTERNAL_QUERY PG_DIAG_CONTEXT PG_DIAG_SCHEMA_NAME PG_DIAG_TABLE_NAME PG_DIAG_COLUMN_NAME PG_DIAG_DATATYPE_NAME PG_DIAG_CONSTRAINT_NAME PG_DIAG_SOURCE_FILE PG_DIAG_SOURCE_LINE PG_DIAG_SOURCE_FUNCTION 43.4 RingPostgreSQL Functions The next functions are define by the RingPostgreSQL Library Reference : https://www.postgresql.org/docs/9.1/static/libpq.html PGconn *PQconnectdbParams(const char **keywords, const char **values,int expand_dbname); PGconn *PQconnectdb(const char *conninfo) PGconn *PQsetdbLogin(const char *pghost,const char *pgport, const char *pgoptions,const char *pgtty, const char *dbName,const char *login,const char *pwd) PGconn *PQsetdb(char *pghost,char *pgport,char *pgoptions, char *pgtty,char *dbName) PGconn *PQconnectStartParams(const char **keywords, const char **values,int expand_dbname) PGconn *PQconnectStart(const char *conninfo) PostgresPollingStatusType PQconnectPoll(PGconn *conn) PQconninfoOption *PQconndefaults(void) PQconninfoOption *PQconninfo(PGconn *conn) PQconninfoOption *PQconninfoParse(const char *conninfo, char **errmsg) void PQfinish(PGconn *conn) void PQreset(PGconn *conn) int PQresetStart(PGconn *conn) PostgresPollingStatusType PQresetPoll(PGconn *conn) PGPing PQpingParams(const char **keywords,const char **values, int expand_dbname) PGPing PQping(const char *conninfo) char *PQdb(const PGconn *conn) char *PQuser(const PGconn *conn) char *PQpass(const PGconn *conn) char *PQhost(const PGconn *conn) char *PQport(const PGconn *conn) 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) 43.4. RingPostgreSQL Functions 345
  • 379.
    Ring Documentation, Release1.10 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, 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, 43.4. RingPostgreSQL Functions 346
  • 380.
    Ring Documentation, Release1.10 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) 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) 43.4. RingPostgreSQL Functions 347
  • 381.
    CHAPTER FORTYFOUR 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 function load the openssllib.ring library load "openssllib.ring" # Use OpenSSL functions • MD5() • SHA1() • SHA256() • SHA512() • SHA384() • SHA224() • Encrypt() • Decrypt() • Randbytes() Before using the next function load the internetlib.ring library load "internetlib.ring" # Use the Internet functions • Download() • SendEmail() 44.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 348
  • 382.
    Ring Documentation, Release1.10 Output: md5('happy') = 56ab24c15b72a457069c5ea42fcfc640 md5('Hello') = 8b1a9953c4611296a827abf8c47804d7 44.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 44.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 44.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 44.2. SHA1() Function 349
  • 383.
    Ring Documentation, Release1.10 Output: sha512('hello') : 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673c a72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043 sha512('apple') : 844d8779103b94c18f4aa4cc0c3b4474058580a991fba85d3ca698a0bc9e52 c5940feb7a65a3a290e17e6b23ee943ecc4f73e7490327245b4fe5d5efb590feb2 sha512('hello world') : 309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca8 6d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f 44.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 44.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 44.7 Encrypt() Function We can use the Encrypt() function to encrypts the data using the Blowfish algorithm. 44.5. SHA384() Function 350
  • 384.
    Ring Documentation, Release1.10 Syntax: Encrypt(cString, cKey, cIV) ---> Encrypted string 44.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 44.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 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 44.8. Decrypt() Function 351
  • 385.
    Ring Documentation, Release1.10 44.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 44.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 44.12 Download() Function Syntax: Download(cURL) ---> String contains the server response Example: cStr= download("http://doublesvsoop.sourceforge.net/") see cStr write("download.txt",cStr) 44.10. File Hash 352
  • 386.
    Ring Documentation, Release1.10 44.13 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 44.13. SendEmail() Function 353
  • 387.
    CHAPTER FORTYFIVE 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() 45.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] ] 354
  • 388.
    Ring Documentation, Release1.10 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 new point { print() } Class Point x = 10 y = 20 z = 30 func print see x + nl + y + nl + z + nl 45.1. Classes and Objects 355
  • 389.
    Ring Documentation, Release1.10 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. 45.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 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 + 45.2. Access Objects Using Braces 356
  • 390.
    Ring Documentation, Release1.10 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 45.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 + "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: 45.3. Composition 357
  • 391.
    Ring Documentation, Release1.10 Name : Rectangle 1 Color: Blue P1 : (10,20) P2 : (200,300) 45.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: Message from SetName() Function! Message from GetName() Function! Mr. Mahmoud Fayed Message from SetName() Function! Message from GetName() Function! Mr. Ahmed Fayed 45.5 Private Attributes and Methods We can define private attributes and methods after the keyword private inside the class body 45.4. Setter and Getter 358
  • 392.
    Ring Documentation, Release1.10 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 Error (R27) : Using private attribute from outside the class : salary Error (R26) : Calling private method from outside the class : increasesalary 45.6 Operator Overloading We can add the operator method to our class to enable using operators with the class objects. Syntax: Class ClassName ... 45.6. Operator Overloading 359
  • 393.
    Ring Documentation, Release1.10 Func operator cOperator,Para ... The function operator takes two paramters, the first represent the operator and the second represent the second param- eter 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 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 45.6. Operator Overloading 360
  • 394.
    Ring Documentation, Release1.10 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" ### 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 45.6. Operator Overloading 361
  • 395.
    Ring Documentation, Release1.10 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 45.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 ... 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 45.7. Inheritance 362
  • 396.
    Ring Documentation, Release1.10 super.print() see "Job : " + job + nl + "Salary : " + salary + nl Output: Name : test Age : 20 Job : programmer Salary : 20000000 45.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! Note: we can write class definitions inside a string then using eval() we can execute the string to define the classes 45.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 45.8. Dynamic Attributes 363
  • 397.
    Ring Documentation, Release1.10 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 45.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 45.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 45.10. Printing Objects 364
  • 398.
    Ring Documentation, Release1.10 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 Other 0 0 0 45.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 45.12. Sort() and List of Objects 365
  • 399.
    Ring Documentation, Release1.10 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 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 45.12. Sort() and List of Objects 366
  • 400.
    Ring Documentation, Release1.10 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 45.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 Whay 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 45.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. 45.13. Using Self.Attribute and Self.Method() 367
  • 401.
    Ring Documentation, Release1.10 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 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 45.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. 45.15. Using This in the class region as Self 368
  • 402.
    Ring Documentation, Release1.10 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 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. 45.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 45.16. Default value for object attributes 369
  • 403.
    CHAPTER FORTYSIX 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 46.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 5 370
  • 404.
    Ring Documentation, Release1.10 aList2 1 4 9 16 25 46.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! 46.3 Higher-order Functions Higher-order functions are the functions that takes other functions as parameters. Example: Func Main times(5,:test) 46.2. First-class Functions 371
  • 405.
    Ring Documentation, Release1.10 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! 46.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 Class great func f1 f2( func { see "Message from f1" + nl } ) func f2 x call x() Output: hello Sum : 6 46.4. Anonymous and Nested Functions 372
  • 406.
    Ring Documentation, Release1.10 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 True False False odd even odd even 46.5 Equality of functions We can test if function = function or not using the ‘=’ or ‘!=’ operators 46.5. Equality of functions 373
  • 407.
    Ring Documentation, Release1.10 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 46.5. Equality of functions 374
  • 408.
    CHAPTER FORTYSEVEN 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() 375
  • 409.
    Ring Documentation, Release1.10 • getattribute() • setattribute() • mergemethods() • packagename() 47.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 47.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() Output: 47.1. locals() Function 376
  • 410.
    Ring Documentation, Release1.10 message from test() Global Variables: x y z 47.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 47.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: Count : 208 len() add() del() get() 47.3. functions() Function 377
  • 411.
    Ring Documentation, Release1.10 clock() ... Note: The complete list is removed from the previous output. 47.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 47.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() func test see isglobal("x") + nl + isglobal("y") + nl + isglobal("z") + nl Output: 1 1 0 47.5. islocal() Function 378
  • 412.
    Ring Documentation, Release1.10 47.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 47.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 Output: 1 1 0 47.9 packages() Function We can get a list of packages names using the packages() function. Syntax: packages() --> a list contains packages names 47.7. isfunction() Function 379
  • 413.
    Ring Documentation, Release1.10 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 47.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: 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 47.10. ispackage() Function 380
  • 414.
    Ring Documentation, Release1.10 Output: 1 1 0 1 47.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 47.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 47.11. classes() Function 381
  • 415.
    Ring Documentation, Release1.10 Output: 0 1 1 47.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 Output: classes in Package1 class1 classes in Package2 class1 class2 class3 47.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 + 47.13. packageclasses() Function 382
  • 416.
    Ring Documentation, Release1.10 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 47.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: o1 = new point o2 = new rect see classname(o1) + nl # print point see classname(o2) + nl # print rect class point class rect 47.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 47.15. classname() Function 383
  • 417.
    Ring Documentation, Release1.10 Class point x y z Output: 021B5808 021B5808 47.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 47.18 attributes() Function We can get the object attributes using the attributes() function Syntax: attributes(object) --> Returns a list contains the object attributes Example: 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 47.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 47.17. isobject() Function 384
  • 418.
    Ring Documentation, Release1.10 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 47.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: 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 47.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 47.20. isattribute() Function 385
  • 419.
    Ring Documentation, Release1.10 Output: 0 0 0 1 1 47.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: 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 47.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: 47.22. ismethod() Function 386
  • 420.
    Ring Documentation, Release1.10 0 1 47.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): 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 47.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: 47.24. addattribute() Function 387
  • 421.
    Ring Documentation, Release1.10 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 ) 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 47.25. addmethod() Function 388
  • 422.
    Ring Documentation, Release1.10 50 150 250 47.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 47.26. getattribute() function 389
  • 423.
    Ring Documentation, Release1.10 See nl + "FindClass: " +" "+ cValue + nl + nl for i = 1 to len(classList) result = getattribute( classList[i], classMember ) 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 47.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 47.27. setattribute() function 390
  • 424.
    Ring Documentation, Release1.10 acolors: List... white blue yellow 47.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 ******************** 47.28. mergemethods() Function 391
  • 425.
    Ring Documentation, Release1.10 three two one ******************** 47.29 packagename() Function We can know the package name of the latest sucessful import command using the packagename() function Syntax: packagename() --> Returns the package name of the latest sucessful import Example: load "weblib.ring" import System.web see packagename() # system.web 47.29. packagename() Function 392
  • 426.
    CHAPTER FORTYEIGHT 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. 48.1 Puts() function print the value then print new line (nl) Syntax: puts(expr) Example: Load "stdlib.ring" Puts("Hello, World!") 48.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: print("nHello, WorldnnHow are you? tt I'm fine!n") x=10 y=20 print("nx value = #{x} , y value = #{y} n") 393
  • 427.
    Ring Documentation, Release1.10 48.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 48.4 GetString() function Get input from the keyboard - return value as string getstring() ---> string 48.5 GetNumber() function Get input from the keyboard - return value as number getnumber() ---> number 48.6 AppPath() function Get the path of the application folder Syntax: AppPath() ---> The path as String Example: Load "stdlib.ring" # Application Path Puts("Test AppPath()") See AppPath() + nl 48.7 JustFilePath() function Get the path of the file, remove the file name. 48.3. Print2Str() Function 394
  • 428.
    Ring Documentation, Release1.10 Syntax: JustFilePath(cFile) ---> The path as String Example: load "stdlib.ring" see justfilePath("b:ringapplicationsrnoternote.ring") Output: b:ringapplicationsrnote 48.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 48.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 48.10 Times() function Execute a Function nCount times Syntax: 48.8. JustFileName() function 395
  • 429.
    Ring Documentation, Release1.10 Times(nCount,function) Example: Load "stdlib.ring" Puts("Test Times()") Times ( 3 , func { see "Hello, World!" + nl } ) 48.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 } ) 48.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 } ) 48.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"," ") 48.11. Map() function 396
  • 430.
    Ring Documentation, Release1.10 48.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"," ,") 48.15 NewList() function Create a two dimensional list Syntax: NewList(nRows,nColumns) ---> new list Example: Load "stdlib.ring" Puts("Test Newlist()") a1 = 3 a2 = 5 chrArray = newlist(a1,a2) numArray = newlist(a1,a2) chrArray[1][1] = "Hello" numArray[1][1] = 987.2 See chrArray[1][1] + nl See numArray[1][1] + nl 48.16 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") 48.14. SplitMany() function 397
  • 431.
    Ring Documentation, Release1.10 48.17 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 48.18 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 48.19 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") 48.20 Factorial() function Return the factorial of a number Syntax: Factorial(number) ---> number Example: 48.17. IsSpecial() function 398
  • 432.
    Ring Documentation, Release1.10 Load "stdlib.ring" Puts("Test Factorial()") see "6 factorial is : " + Factorial(6) 48.21 Fibonacci() function Return the fibonacci number Syntax: Fibonacci(number) ---> number Example: Load "stdlib.ring" Puts("Test Fibonacci()") see "6 Fibonacci is : " + Fibonacci(6) 48.22 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 48.23 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 48.21. Fibonacci() function 399
  • 433.
    Ring Documentation, Release1.10 48.24 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") 48.25 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")) 48.26 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 48.27 EndsWith() function Returns true if the given string ends with the specified substring. Trailing white spaces are ignored. 48.24. List2File() function 400
  • 434.
    Ring Documentation, Release1.10 Syntax: Endswith(string, substring) ---> True/False Example: Load "stdlib.ring" Puts("Test Endswith()") see endsWith("CalmoSoft", "Soft") + nl 48.28 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 48.29 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 48.30 SumList() function Compute the sum of a list of integers. Syntax: sumlist(list) ---> number Example: Load "stdlib.ring" Puts("Test Sumlist()") 48.28. GCD() function 401
  • 435.
    Ring Documentation, Release1.10 aList = [1,2,3,4,5] see Sumlist(aList) + nl 48.31 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 48.32 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 48.33 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) 48.31. ProdList() function 402
  • 436.
    Ring Documentation, Release1.10 see "" + aList[i] + " " next 48.34 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) 48.35 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 48.36 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) 48.34. IsPalindrome() function 403
  • 437.
    Ring Documentation, Release1.10 48.37 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) 48.38 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) 48.39 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 48.37. MatrixMulti() function 404
  • 438.
    Ring Documentation, Release1.10 48.40 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 48.41 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) 48.42 SubString() function Return a position of a substring starting from a given position in a string. Syntax: Substring(str,substr,npos) ---> string Example: Load "stdlib.ring" # Return a position of a substring starting from a given position in a string. 48.40. Permutation() function 405
  • 439.
    Ring Documentation, Release1.10 Puts("Test Substring()") a = "abcxyzqweabc" b = "abc" i = 4 see substring(a,b,i) 48.43 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 48.44 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 48.45 IsMainSourceFile() function Check if the current file is the main source file Syntax: IsMainSourceFile() ---> True/False Example: Load "stdlib.ring" if ismainsourcefile() # code ok 48.43. ChangeString() function 406
  • 440.
    Ring Documentation, Release1.10 48.46 DirExists() function Check if directory exists Syntax: DirExists(String) ---> True/False Example: Load "stdlib.ring" see "Check dir : b:ring " puts( DirExists("b:ring") ) see "Check dir : C:ring " Puts( DirExists("C:ring") ) 48.47 MakeDir() function Make Directory Syntax: MakeDir(String) Example: Load "stdlib.ring" # Create Directory puts("create Directory : myfolder") makedir("myfolder") 48.48 Fsize() function The function return the file size in bytes. Syntax: FSize(File Handle) ---> Number (File Size in Bytes) 48.49 TrimAll() function Remove all spaces and tabs characters from a string Syntax: TrimAll(cString) ---> cString # Without Spaces and Tabs 48.46. DirExists() function 407
  • 441.
    Ring Documentation, Release1.10 48.50 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 48.51 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 48.52 EpochTime() function Return the Epoch Time Syntax: EpochTime(cDate,cTime) ---> nEpochTime Example: see EpochTime( Date(), Time() ) 48.53 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 48.54 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: 48.50. TrimLeft() function 408
  • 442.
    Ring Documentation, Release1.10 aList = ListAllFiles("c:/ring/ringlibs","ring") # *.ring only aList = sort(aList) see aList Example: see listallfiles("b:/ring/ringlibs/weblib","") # All Files 48.55 SystemSilent() Function We can execute system commands using the SystemSilent() function to avoid displaying the output! Syntax: SystemSilent(cCommand) 48.56 OSCreateOpenFolder() Function Create folder then change the current folder to this new folder Syntax: OSCreateOpenFolder(cCommand) 48.57 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") 48.58 OSDeleteFolder() Function Delete Folder in the current Directory Syntax: OSDeleteFolder(cFolderName) 48.55. SystemSilent() Function 409
  • 443.
    Ring Documentation, Release1.10 48.59 OSCopyFile() Function Copy File to the current directory Syntax: OSCopyFile(cFileName) 48.60 OSDeleteFile() Function Delete File Syntax: OSDeleteFile(cFileName) 48.61 OSRenameFile() Function Rename File Syntax: OSRenameFile(cOldFileName,cNewFileName) 48.62 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 ] 48.63 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 48.59. OSCopyFile() Function 410
  • 444.
    Ring Documentation, Release1.10 48.64 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 48.64. ASCIIList2Str() 411
  • 445.
    CHAPTER FORTYNINE 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 49.1 StdBase Class Attributes: • vValue : Object Value 412
  • 446.
    Ring Documentation, Release1.10 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) 49.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() 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 49.2. String Class 413
  • 447.
    Ring Documentation, Release1.10 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 1 -1 one two three 4 1234 List Items one two three the - position : 12 49.2. String Class 414
  • 448.
    Ring Documentation, Release1.10 Ring programming language Ring ***Ring*** programming language ******Ring****** programming language FirstSecond FirstFirstFirst FirstFirstFirst one two three Hello How are you? 49.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 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" ] ) 49.3. List Class 415
  • 449.
    Ring Documentation, Release1.10 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 two 3 three Search two : 2 Search 1 : 1 Egypt USA KSA 1 2 3 4 5 6 7 one two 49.3. List Class 416
  • 450.
    Ring Documentation, Release1.10 three four 49.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 4 three two one 49.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 49.4. Stack Class 417
  • 451.
    Ring Documentation, Release1.10 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 49.6 HashTable Class Parent Class : List Class Methods: 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: 49.6. HashTable Class 418
  • 452.
    Ring Documentation, Release1.10 Test the hashtable Class Methods Cairo Riyadh 1 0 2 Egypt Cairo KSA Riyadh ************************************************************ Egypt Cairo 49.7 Tree Class Data: Attribute Description Data Node Value Children Children List Methods: 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") } 49.7. Tree Class 419
  • 453.
    Ring Documentation, Release1.10 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... 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 49.8 Math Class Methods: 49.8. Math Class 420
  • 454.
    Ring Documentation, Release1.10 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 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 49.8. Math Class 421
  • 455.
    Ring Documentation, Release1.10 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 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 49.8. Math Class 422
  • 456.
    Ring Documentation, Release1.10 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 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 49.8. Math Class 423
  • 457.
    Ring Documentation, Release1.10 49.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 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 49.9. DateTime Class 424
  • 458.
    Ring Documentation, Release1.10 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 49.10 File Class Methods: 49.10. File Class 425
  • 459.
    Ring Documentation, Release1.10 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() 49.11 System Class Methods: 49.11. System Class 426
  • 460.
    Ring Documentation, Release1.10 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 49.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: 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) 49.12. Debug Class 427
  • 461.
    Ring Documentation, Release1.10 catch see "assert" + nl done raise("Error!") 49.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 hexdecimal 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 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 49.13. DataType Class 428
  • 462.
    Ring Documentation, Release1.10 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 49.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" 49.14. Conversion Class 429
  • 463.
    Ring Documentation, Release1.10 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 49.15 ODBC Class Methods: 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 49.15. ODBC Class 430
  • 464.
    Ring Documentation, Release1.10 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() } 49.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 49.16. MySQL Class 431
  • 465.
    Ring Documentation, Release1.10 Execute Query Print Result Id Name Salary 1 Mahmoud 15000 2 Samir 16000 3 Fayed 17000 Close database 49.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 49.17. SQLite Class 432
  • 466.
    Ring Documentation, Release1.10 see t[2] + nl next next see copy("*",50) + nl for x in aResult see x["name"] + nl next close() } 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 49.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 { 49.18. PostgreSQL Class 433
  • 467.
    Ring Documentation, Release1.10 sql = "CREATE TABLE COMPANY_TEST(" + "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_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 ************************************************** 49.18. PostgreSQL Class 434
  • 468.
    Ring Documentation, Release1.10 49.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 } 49.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") } 49.19. Security Class 435
  • 469.
    CHAPTER FIFTY 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 50.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: Item 4 is a list contains 3 items 1 2 436
  • 470.
    Ring Documentation, Release1.10 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 50.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 x: 100.000000 y: 200.000000 z: 300.000000 Example(2): 50.2. Composition and Returning Objects and Lists by Reference 437
  • 471.
    Ring Documentation, Release1.10 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 } } 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 50.2. Composition and Returning Objects and Lists by Reference 438
  • 472.
    Ring Documentation, Release1.10 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 50.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! 50.4 Declarative Programming on the top of Object-Oriented The next features enable us to build and use declartive 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: # Declartive Programming (Nested Structures) Screen() { point() { x = 100 y = 200 z = 300 } 50.3. Executing code after the end of object access 439
  • 473.
    Ring Documentation, Release1.10 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! 50.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 direcly 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 { 50.5. More beautiful Code 440
  • 474.
    Ring Documentation, Release1.10 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 50.5. More beautiful Code 441
  • 475.
    CHAPTER FIFTYONE NATURAL LANGUAGE PROGRAMMING Usingthe Ring programming language, we can create Natural programming languages based on classes and objects. 51.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. 51.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 442
  • 476.
    Ring Documentation, Release1.10 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 51.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 { I want window and the window title = "hello world" } Class App 51.3. Change the Ring Keyword ‘And’ 443
  • 477.
    Ring Documentation, Release1.10 # 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 51.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: 51.4. Change the Ring Operator ‘+’ 444
  • 478.
    Ring Documentation, Release1.10 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 51.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 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 51.5. Change the ‘=’ operator to ‘is’ 445
  • 479.
    Ring Documentation, Release1.10 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 51.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 ' + 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 51.6. Using Eval() with our Natural Code 446
  • 480.
    Ring Documentation, Release1.10 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 51.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: 51.7. BraceStart and BraceEnd Methods 447
  • 481.
    Ring Documentation, Release1.10 start Hello end start end 51.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 51.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 51.8. BraceExprEval Method 448
  • 482.
    Ring Documentation, Release1.10 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 51.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") 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 } 51.10. BraceError() Method 449
  • 483.
    Ring Documentation, Release1.10 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... 51.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 { 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 51.11. Clean Natural Code 450
  • 484.
    Ring Documentation, Release1.10 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,":") while c > 0 c= substr(cCatchError,":") cCatchError=substr(cCatchError,c+1) end literal += substr(cCatchError,1) 51.11. Clean Natural Code 451
  • 485.
    CHAPTER FIFTYTWO 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) 52.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. 452
  • 486.
    Ring Documentation, Release1.10 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) RunFile("program.txt") } We defined a language called MyLanguage, We have folder for the language commands. 52.1. Natural Library - Demo Program 453
  • 487.
    Ring Documentation, Release1.10 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) } ]) 52.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) 52.2. Defining Commands 454
  • 488.
    Ring Documentation, Release1.10 • 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. 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) } ]) 52.2. Defining Commands 455
  • 489.
    Ring Documentation, Release1.10 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 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 52.2. Defining Commands 456
  • 490.
    Ring Documentation, Release1.10 52.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! ") } 52.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 52.3. Natural Library - Operators 457
  • 491.
    Ring Documentation, Release1.10 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 } 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) 52.4. Defining commands using classes 458
  • 492.
    CHAPTER FIFTYTHREE WEB DEVELOPMENT (CGILIBRARY) In this chapter we will learn about developing Web applications using a CGI Library written in the Ring language. 53.1 Configure the Apache web server We can use Ring with any web server that support CGI. In this section we will learn about using Ring with the Apache HTTP Server. You can download Apache from : http://httpd.apache.org/ Or you can get it included with other projects like XAMPP : https://www.apachefriends.org/download.html Install then open the file: xamppapacheconfhttpd.conf search for <Directory /> Then after it add Options FollowSymLinks +ExecCGI So we have <Directory /> Options FollowSymLinks +ExecCGI Search for the next line and be 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 AddHandler cgi-script .cgi .ring Example AddHandler cgi-script .cgi .pl .asp .ring 459
  • 493.
    Ring Documentation, Release1.10 Run/Start the server Create your web applications in a directory supported by the web server. Example: Apache2.2htdocsmywebapplicationfolder Example: xampphtdocsmywebapplicationfolder Inside the source code file (*.ring), Add this line #!ring -cgi Note: Change the previous line based on the path to ring.exe in your machine 53.2 Ring CGI Hello World Program The next program is the Hello World program #!ring -cgi See "content-type: text/html" +nl+nl+ "Hello World!" + nl 53.3 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!") } Example (2) : #!ring -cgi Load "weblib.ring" Import System.Web WebPage() { Text("Hello World!") } 53.2. Ring CGI Hello World Program 460
  • 494.
    Ring Documentation, Release1.10 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. 53.4 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 53.5 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) ]) divstart([:style = stylefloatleft() + stylesize("100px","100%") + stylecolor("black") + stylegradient(58)]) formstart("ex5.ring") tablestart([ :style = stylesize("65%","90%") + stylemarginleft("35%") + stylemargintop("30%") ]) rowstart([]) cellstart([]) text ( "Name : " ) cellend() cellstart([]) cTextboxStyle = StyleMarginLeft("5%") + StyleWidth("250px") + StyleColor("black") + 53.4. Web Library Features 461
  • 495.
    Ring Documentation, Release1.10 StyleBackColor("white") textbox([ :name = "Name", :style = cTextboxStyle ] ) cellend() rowend() rowstart([]) cellstart([]) text ( "Address : " ) cellend() cellstart([]) textbox([ :name = "Address", :style = cTextboxStyle] ) cellend() rowend() rowstart([]) cellstart([]) text ( "Phone : " ) cellend() cellstart([]) textbox([ :name = "Phone", :style = cTextboxStyle ]) cellend() rowend() rowstart([]) cellstart([]) text ( "Age : " ) cellend() cellstart([]) textbox([ :name = "Age", :style = cTextboxStyle ]) cellend() rowend() rowstart([]) cellstart([]) text ( "City: " ) cellend() cellstart([]) listbox([ :name = "City", :items = ["Cairo","Riyadh","Jeddah"], :style = stylemarginleft("5%") + stylewidth("400px") ] ) cellend() rowend() rowstart([]) cellstart([]) text ( "Country : " ) cellend() cellstart([]) combobox([ :name = "Country", :items = ["Egypt","Saudi Arabia","USA"], :style = stylemarginleft("5%") + stylewidth("400px")+ stylecolor("black")+ stylebackcolor("white")+ stylefontsize("14px") ]) cellend() rowend() rowstart([]) cellstart([]) text ( "Note : " ) cellend() cellstart([]) editbox([ :name = "Notes", :style = stylemarginleft("5%") + 53.5. HTTP Get Example 462
  • 496.
    Ring Documentation, Release1.10 stylesize("400px","100px")+ stylecolor("black")+ stylebackcolor("white") , :value = "write comments here..." ] ) cellend() rowend() rowstart([]) cellstart([]) cellend() cellstart([]) submit([ :value = "Send" , :Style = stylemarginleft("5%") ]) cellend() rowend() tableend() formend() divend() divend() divend() } Screen Shot: 53.5. HTTP Get Example 463
  • 497.
    Ring Documentation, Release1.10 The Response #!ring -cgi Load "weblib.ring" Import System.Web New Page { divstart([ :style = styledivcenter("800px","500px") ]) boxstart() text ( "HTTP GET Response" ) newline() boxend() divstart([ :style = stylefloatleft()+stylewidth("10%")+ 53.5. HTTP Get Example 464
  • 498.
    Ring Documentation, Release1.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: 53.5. HTTP Get Example 465
  • 499.
    Ring Documentation, Release1.10 53.6 HTTP POST Example The Page User Interface #!ring -cgi Load "weblib.ring" Import System.Web New Page { boxstart() text( "Post Test") newline() boxend() divstart([ :style=StyleFloatLeft()+StyleWidth("100px") ]) newline() text( "Number1 : " ) newline() newline() text( "Number2 : " ) newline() newline() divend() formpost("ex7.ring") divstart([ :style = styleFloatLeft()+StyleWidth("200px") ]) newline() textbox([ :name = "Number1" ]) newline() newline() textbox([ :name = "Number2" ]) newline() newline() submit([ :value = "Send" ] ) divend() formend() } Screen Shot: 53.6. HTTP POST Example 466
  • 500.
    Ring Documentation, Release1.10 The Response #!ring -cgi Load "weblib.ring" Import System.Web New Page { boxstart() text( "Post Result" ) newline() boxend() divstart([ :style = styleFloatLeft()+styleWidth("200px") ]) newline() text( "Number1 : " + aPageVars["Number1"] ) newline() newline() text( "Number2 : " + aPageVars["Number2"] ) newline() newline() text( "Sum : " + (0 + aPageVars["Number1"] + aPageVars["Number2"] ) ) newline() divend() } Screen Shot: 53.6. HTTP POST Example 467
  • 501.
    Ring Documentation, Release1.10 53.7 Upload Files The Page User Interface #!ring -cgi Load "weblib.ring" Import System.Web New page { boxstart() text( "Upload File" ) newline() boxend() for x = 1 to 3 newline() next formupload("ex9.ring") text( "Customer Name : " ) textbox([ :name = "custname" ]) newline() newline() divstart([ :style = styleFloatLeft() + styleWidth("90px") ]) uploadfile("file") newline() newline() uploadfile("file2") newline() newline() submit([ :value = "Send" ]) divend() formend() } Screen Shot: 53.7. Upload Files 468
  • 502.
    Ring Documentation, Release1.10 The Response #!ring -cgi Load "weblib.ring" Import System.Web cUploadPath = "C:/Apache2.2/htdocs/ringapp/upload/" cUploadFolder = "/ringapp/upload/" New page { boxstart() text( "Upload Result" ) newline() boxend() newline() divstart([ :style= styleFloatLeft() + styleWidth("100px") ]) text( "Name : " + aPageVars["custname"] ) newline() divend() if aPageVars["file"] != char(13) getuploadedfile(self,"file") ok if aPageVars["file2"] != char(13) getuploadedfile(self,"file2") ok } Func getuploadedfile oObj,cFile # here we use object.property # instead of object { } to avoid executing braceend method cFileName = cUploadPath + oObj.getfilename(aPageVars,cFile) 53.7. Upload Files 469
  • 503.
    Ring Documentation, Release1.10 write(cFileName,aPageVars[cFile]) system("chmod a+x "+cFileName) oObj.newline() oObj.text( "File "+cFileName+ " Uploaded ..." ) oObj.newline() imageURL = cUploadFolder + oObj.getfilename(aPageVars,cFile) oObj.link([ :url = imageURL, :title = "Download" ]) oObj.newline() oObj.image( [ :url = imageURL , :alt = :image ] ) oObj.newline() Screen Shot: 53.7. Upload Files 470
  • 504.
    Ring Documentation, Release1.10 53.8 Cookies The Page User Interface #!ring -cgi Load "weblib.ring" 53.8. Cookies 471
  • 505.
    Ring Documentation, Release1.10 Import System.Web New page { boxstart() text( "Cookie Test" ) newline() boxend() newline() link([ :url = "ex11.ring", :title = "Use Cookies" ]) cookie("custname","Mahmoud Fayed") cookie("custage",28) } Screen Shot: The Response #!ring -cgi Load "weblib.ring" Import System.Web New Page { boxstart() text( "Cookies Values" ) newline() boxend() link([ :url = "ex10.ring", :title = "back" ]) newline() divstart([:style="float:left;width:200px"]) text( "Name : " + aPageVars["custname"] ) newline() text( "Age : " + aPageVars["custage"] ) newline() divend() } Screen Shot: 53.8. Cookies 472
  • 506.
    Ring Documentation, Release1.10 53.9 URL Encode The Page User Interface #!ring -cgi Load "weblib.ring" Import System.Web New Page { boxstart() text( "URLEncode" ) newline() boxend() link([ :url = "ex5.ring?Name="+URLEncode("-*{Mahmoud}*-")+ "&Address=Egypt&Phone=123456&Age=28&Notes=Programmer", :title = "Test URL Encode" ]) } Screen Shot: Screen Shot: 53.9. URL Encode 473
  • 507.
    Ring Documentation, Release1.10 53.10 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 New NumbersController { start() } 53.10. Templates 474
  • 508.
    Ring Documentation, Release1.10 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: 53.10. Templates 475
  • 509.
    Ring Documentation, Release1.10 53.11 HTML Special Characters The text() function display HTML special characters. If you want to write html code, use the html() function. 53.11. HTML Special Characters 476
  • 510.
    Ring Documentation, Release1.10 #!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: 53.12 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") ]) newline() text( "Value : " ) newline() newline() divend() formpost("ex16.ring") divstart([ :style = StyleFloatLeft() + StyleWidth("300px") ]) newline() 53.12. Hash Functions 477
  • 511.
    Ring Documentation, Release1.10 textbox([ :name = "Value" ]) newline() newline() submit([ :value = "Send" ]) divend() formend() } Screen Shot: The Response #!ring -cgi Load "weblib.ring" Import System.Web New Page { boxstart() text( "Hash Result" ) newline() boxend() divstart([ :style = styleFloatLeft() + styleWidth("100%") ]) newline() text( "Value : " + aPageVars["Value"] ) newline() text( "MD5 : " + MD5(aPageVars["Value"]) ) newline() text( "SHA1 : " + SHA1(aPageVars["Value"]) ) newline() text( "SHA256 : " + SHA256(aPageVars["Value"]) ) newline() text( "SHA224 : " + SHA224(aPageVars["Value"]) ) newline() text( "SHA384 : " + SHA384(aPageVars["Value"]) ) newline() text( "SHA512 : " + SHA512(aPageVars["Value"]) ) newline() divend() } Screen Shot: 53.12. Hash Functions 478
  • 512.
    Ring Documentation, Release1.10 53.13 Random Image #!ring -cgi Load "weblib.ring" Import System.Web cUploadPath = "C:/Apache2.2/htdocs/ringapp/upload/" New Page { boxstart() text( "Random Test") newline() boxend() divstart([ :style = styleFloatLeft() + styleWidth("400px") ]) newline() aList = dir(cUploadPath) if len(aList) > 0 nIndex = random(len(aList)) if nindex = 0 nIndex = 1 ok cItem = "upload/" + aList[nIndex][1] newline() image( [ :url = cItem , :alt = :image ] ) else text("No images!") newline() ok divend() } Screen Shot: 53.13. Random Image 479
  • 513.
    Ring Documentation, Release1.10 53.14 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 listart([]) 53.14. HTML Lists 480
  • 514.
    Ring Documentation, Release1.10 cFuncName = "btn"+x+"()" button([ :onclick = cFuncName , :value = x]) script(scriptfuncalert(cFuncName,string(x))) liend() next ulend() } Screen Shot: 53.14. HTML Lists 481
  • 515.
    Ring Documentation, Release1.10 53.15 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: 53.15. HTML Tables 482
  • 516.
    Ring Documentation, Release1.10 53.16 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: 53.16. Gradient 483
  • 517.
    Ring Documentation, Release1.10 53.17 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 { TD { WIDTH="10%" text("Name : " ) } 53.17. Generating Pages using Objects 484
  • 518.
    Ring Documentation, Release1.10 TD { Input { type = "text" } } } TR { TD { WIDTH="10%" text("Email : " ) } TD { Input { type = "text" } } } TR { TD { WIDTH="10%" text("Password : " ) } TD { Input { type = "password" } } } TR { TD { WIDTH="10%" text("Notes") } TD { TextArea { width="100%" rows = 10 cols = 10 text("type text here...") } } } TR { TD { WIDTH="10%" text("Gender") } TD { select { width = "100%" option { text("Male") } option { text("Female") } } } } TR { TD { WIDTH="10%" text("Role") } TD { select { multiple = "multiple" width = "100%" option { text("student") } option { text("admin") } } } } } Input { type = "submit" value = "send" } Image { src="upload/profile1.jpg" alt="profile"} Input { type = "checkbox" value = "Old Member"} text("old member") Input { type = "range" min=1 max=100} Input { type = "number" min=1 max=100} Input { type = "radio" color="black" name="one" value = "one"} text("one") } } div { color = "white" 53.17. Generating Pages using Objects 485
  • 519.
    Ring Documentation, Release1.10 backgroundcolor = "blue" width = "100%" UL { LI { TEXT("ONE") } LI { TEXT("TWO") } LI { TEXT("THREE") } } } div { audio { src = "horse.ogg" type = "audio/ogg" } video { width = 320 height = 240 src = "movie.mp4" type = "video/mp4" } Input { type = "color" value = "#ff0000" onchange = "clickColor(0, -1, -1, 5)" } } } Screen Shot: 53.17. Generating Pages using Objects 486
  • 520.
    Ring Documentation, Release1.10 53.17. Generating Pages using Objects 487
  • 521.
    Ring Documentation, Release1.10 53.18 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 53.18. HtmlPage Class 488
  • 522.
    Ring Documentation, Release1.10 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()) 53.19 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" ]) divstart([ :class = "jumbotron" ]) h1("Bootstrap Page") divend() 53.19. Using Bootstrap Library using Functions 489
  • 523.
    Ring Documentation, Release1.10 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: 53.20 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 53.20. Using Bootstrap Library using Objects 490
  • 524.
    Ring Documentation, Release1.10 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-sucess btn-sm" text("sucess") } 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") } } div { classname = "col-sm-4" Button { classname = "btn btn-default btn-block" text("default") } Button { classname = "btn btn-primary btn-block" text("primary") } Button { classname = "btn btn-sucess btn-block" text("sucess") } Button { classname = "btn btn-info btn-block" text("info") } Button { classname = "btn btn-warning btn-block" text("warning") } Button { classname = "btn btn-danger btn-block" text("danger") } Button { classname = "btn btn-link btn-block" text("link") } } 53.20. Using Bootstrap Library using Objects 491
  • 525.
    Ring Documentation, Release1.10 div { classname = "col-sm-4" div { classname = "btn-group" button { classname="btn btn-primary" text("one") } button { classname="btn btn-primary" text("two") } button { classname="btn btn-primary" text("three") } } } div { classname = "col-sm-4" div { classname = "btn-group btn-group-lg" button { classname="btn btn-primary" text("one") } button { classname="btn btn-primary" text("two") } button { classname="btn btn-primary" text("three") } } } div { classname = "col-sm-4" div { classname = "btn-group-vertical btn-group-lg" button { classname="btn btn-primary" text("one") } button { classname="btn btn-primary" text("two") } button { classname="btn btn-primary" text("three") } } } } div { classname="modal fade" id="myModal" role="dialog" div { classname = "modal-dialog modal-lg" div { classname="modal-content" div { classname="modal-header" button { classname="close" datadismiss="modal" html("&times") } h4 { classname="modal-title" text("Modal Header") } } div { classname = "modal-body" p { text("This is a large model.") } } div { classname="modal-footer" button { classname = "btn btn-default" datadismiss="modal" text("close") } } } } } } } Screen Shot: 53.20. Using Bootstrap Library using Objects 492
  • 526.
    Ring Documentation, Release1.10 53.21 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. #!ring -cgi Load "weblib.ring" Load "datalib.ring" Import System.Web website = "ex24.ring" New SalaryController { Routing() } 53.21. CRUD Example using MVC 493
  • 527.
    Ring Documentation, Release1.10 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: 53.21. CRUD Example using MVC 494
  • 528.
    Ring Documentation, Release1.10 53.22 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 53.22. Users registration and Login 495
  • 529.
    Ring Documentation, Release1.10 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" Load "datalib.ring" Load "ex25_users.ring" Import System.Web website = "ex25.ring" New UsersController { Routing() } Screen Shot: 53.22. Users registration and Login 496
  • 530.
    Ring Documentation, Release1.10 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") cellend() cellstart([ :style = stylewidth("80%") ]) textbox([:name = "username", :style = stylewidth("100%")]) cellend() rowend() rowstart([]) cellstart([ :Style = styleheight(30)]) text("Password") cellend() cellstart([]) textbox([:name = "password" , :type = "password"]) 53.22. Users registration and Login 497
  • 531.
    Ring Documentation, Release1.10 cellend() rowend() rowstart([]) cellstart([ :style = styleheight(30)]) text("Email") cellend() cellstart([]) textbox([:name = "email" , :style = stylewidth("100%")]) cellend() rowend() rowstart([]) cellstart([ :style = styleheight(30)]) cellend() cellstart([ :style = styleheight(30)]) submit([:value = "Register" ]) cellend() rowend() tableend() formend() divend() divend() } Screen Shot: The Registration response #!ring -cgi Load "weblib.ring" Load "datalib.ring" Load "ex25_users.ring" 53.22. Users registration and Login 498
  • 532.
    Ring Documentation, Release1.10 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"]) text("New User Created!") newline() text("User Name : " + aPageVars["username"]) newline() } oUser.Disconnect() See the next code for the Login page #!ring -cgi Load "weblib.ring" Load "datalib.ring" Import System.Web website = "ex28.ring" new page { boxstart() text( "Login") newline() boxend() divstart([:style = stylegradient(6) + stylesize("100%","95%") ]) link([ :url = website, :title = "back" , :style = stylecolor("white")]) newline() divstart([ :style= styledivcenter("500","130") + stylegradient(52) ]) formpost("ex29.ring") tablestart([ :Style = stylemarginleft("2%") + stylemargintop("2%") + stylewidth("90%") ]) rowstart([]) cellstart([:style = stylewidth("20%") + styleheight(30)]) text("User Name") cellend() cellstart([ :style = stylewidth("80%") ]) textbox([:name = "username", :style = stylewidth("100%")]) cellend() 53.22. Users registration and Login 499
  • 533.
    Ring Documentation, Release1.10 rowend() rowstart([]) cellstart([ :style = styleheight(30)]) text("Password") cellend() cellstart([]) textbox([:name = "password" , :type = "password"]) cellend() rowend() rowstart([]) cellstart([ :style = styleheight(30) ]) cellend() cellstart([]) submit([:value = "Login" ]) cellend() rowend() tableend() formend() divend() divend() } Screen Shot: The response page #!ring -cgi Load "weblib.ring" Load "datalib.ring" Load "ex25_users.ring" Import System.Web 53.22. Users registration and Login 500
  • 534.
    Ring Documentation, Release1.10 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 #!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() 53.23 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 53.23. Database, ModelBase & ControllerBase classes 501
  • 535.
    Ring Documentation, Release1.10 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) 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]) + "'," 53.23. Database, ModelBase & ControllerBase classes 502
  • 536.
    Ring Documentation, Release1.10 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) 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 53.23. Database, ModelBase & ControllerBase classes 503
  • 537.
    Ring Documentation, Release1.10 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 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 53.23. Database, ModelBase & ControllerBase classes 504
  • 538.
    Ring Documentation, Release1.10 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" 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 53.23. Database, ModelBase & ControllerBase classes 505
  • 539.
    Ring Documentation, Release1.10 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 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() 53.24 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 53.24. WebLib API 506
  • 540.
    Ring Documentation, Release1.10 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. 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. 53.24. WebLib API 507
  • 541.
    Ring Documentation, Release1.10 53.25 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. 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. 53.26 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> Continued on next page 53.25. Application Class 508
  • 542.
    Ring Documentation, Release1.10 Table 53.2 – continued from previous page Method Parameters Description 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> 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 53.26. Page Class 509
  • 543.
    Ring Documentation, Release1.10 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 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 53.27 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 53.27. ScriptFunctions Class 510
  • 544.
    Ring Documentation, Release1.10 53.28 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. 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;” 53.29 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. 53.28. StyleFunctions Class 511
  • 545.
    Ring Documentation, Release1.10 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. 53.30 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 53.30. HtmlPage Class 512
  • 546.
    CHAPTER FIFTYFOUR DEPLOYING WEB APPLICATIONSIN THE CLOUD In this chapter we will learn about deploying Ring Web Applications in the Cloud using Heroku 54.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/ 54.2 Usage To use this project and deploy it on Heroku 513
  • 547.
    Ring Documentation, Release1.10 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 projet 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 54.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" If you are using TortoiseGit, From windows explorer, select the file Right click —> Properties —> Git —> Executable (+x) Then commit and deploy! 54.3. Ring source code files and permissions 514
  • 548.
    Ring Documentation, Release1.10 54.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!") } 54.5 Application Database When you depoly 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 54.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 54.4. Hello World program 515
  • 549.
    Ring Documentation, Release1.10 54.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) 54.7. Local Tests 516
  • 550.
    CHAPTER FIFTYFIVE USING RINGLIBCURL In thischapter we will learn about using RingLibCurl 55.1 Get Request Example: load "libcurl.ring" curl = curl_easy_init() curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1) curl_easy_setopt(curl, CURLOPT_URL, "http://ring-lang.sf.net") curl_easy_perform(curl) curl_easy_cleanup(curl) 55.2 Post Request Example: load "libcurl.ring" curl = curl_easy_init() cPostThis = "page=4&Number1=4&Number2=5" curl_easy_setopt(curl, CURLOPT_URL, "http://localhost/ringapp/index.ring?page=3") curl_easy_setopt(curl, CURLOPT_POSTFIELDS, cPostThis) curl_easy_perform(curl) curl_easy_cleanup(curl) 55.3 Facebook Login Example: 517
  • 551.
    Ring Documentation, Release1.10 load "libcurl.ring" see "Enter Email : " give $login_email See "Enter Password : " give $login_pass curl = curl_easy_init() curl_easy_setopt(curl, CURLOPT_URL, 'https://www.facebook.com/login.php') curl_easy_setopt(curl, CURLOPT_POSTFIELDS,'charset_test=j u s t a t e s t'+ ' &email='+urlencode($login_email)+'&pass='+ urlencode($login_pass)+'&login=Login') curl_easy_setopt(curl, CURLOPT_POST, 1) curl_easy_setopt(curl, CURLOPT_HEADER, 0) curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1) curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "cookies.txt") curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "cookies.txt") curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U;"+ " Windows NT 5.1; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3") curl_easy_setopt(curl, CURLOPT_REFERER, "http://www.facebook.com") curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE) curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2) mylist = curl_slist_append(NULL,'Accept-Charset: utf-8') curl_slist_append(mylist,'Accept-Language: en-us,en;q=0.7,bn-bd;q=0.3') curl_slist_append(mylist,'Accept: text/xml,application/xml,'+ 'application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5') curl_easy_setopt(curl, CURLOPT_HTTPHEADER, mylist) curl_easy_setopt(curl, CURLOPT_COOKIESESSION, false) curl_easy_perform(curl) curl_easy_cleanup(curl) Func URLEncode cStr cOut = "" for x in cStr if isalnum(x) cOut += x but x = " " cOut += "+" else cOut += "%"+str2hex(x) ok next return cOut 55.4 Save Output to String Example: load "libcurl.ring" curl = curl_easy_init() curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1) 55.4. Save Output to String 518
  • 552.
    Ring Documentation, Release1.10 curl_easy_setopt(curl, CURLOPT_URL, "http://ring-lang.sf.net") cOutput = curl_easy_perform_silent(curl) See "Output:" + nl see cOutput curl_easy_cleanup(curl) 55.5 Get Stock Data From Yahoo Example: Load "libcurl.ring" ### Part 1 --- Get Crumb and Cookie ----------------------------------------- See "Start curl_easy_init(): "+ nl curl = curl_easy_init() ### >>> HANDLE >>> 01006BD0 CURL 0 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1) curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "cookies.txt") curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "cookies.txt") curl_easy_setopt(curl, CURLOPT_URL, "https://finance.yahoo.com/quote/AMZN/history") ### HTML Data >>> STDOUT Window, Use curl_easy_perform_silent >>> String cOutput = curl_easy_perform_silent(curl) ### GO Get Data >>> String ### Extract Crumb from data ### "CrumbStore":{"crumb":"abcdefghijk"}, if cOutput != NULL newStr1 = substr(cOutput, substr(cOutput, '"CrumbStore":{"crumb":"' ), 48 ) nPosS = substr(newStr1, ':"' ) ; ### Start of crumb -2 nPosE = substr(newStr1, '"}' ) ; ### End of crumb nCount = nPosE - nPosS -2 ### size of crumb myCrumb = substr(newStr1, nPosS +2, nCount) See "myCrumb.: |"+ myCrumb +"|" +nl ### UniCode "u002F" replace it with "/" if substr( myCrumb, "u002F") myCrumb = substr( myCrumb, "u002F", "/") See "myCrumb2: |"+ myCrumb +"|"+ nl ok else See "No Connectivity to Yahoo. Looking for Cookie and Crumb." +nl +nl ok ### Part 2 --- Send URL with Crumb, and Cookie ----------------------------------------- 55.5. Get Stock Data From Yahoo 519
  • 553.
    Ring Documentation, Release1.10 ### Send URL+Crumb to Yahoo to fetch 1st stock history data, $url = "https://query1.finance.yahoo.com/v7/finance/download/AMZN"+ "?period1=1277856000&period2=1498777545&interval=1wk" + "&events=history&crumb=" + myCrumb curl_easy_setopt(curl, CURLOPT_URL, $url); cStr = curl_easy_perform_silent(curl) See cStr curl_easy_cleanup(curl) ### REMEMBER to CLOSE CURL Output: myCrumb.: |sEEeW97mxvN| Date,Open,High,Low,Close,Adj Close,Volume 2010-07-05,110.650002,117.480003,109.000000,117.260002,117.260002,21000400 2010-07-12,117.809998,124.879997,117.320000,118.489998,118.489998,29407300 2010-07-19,118.379997,121.250000,105.800003,118.870003,118.870003,74252100 55.5. Get Stock Data From Yahoo 520
  • 554.
    CHAPTER FIFTYSIX USING RINGZIP In thischapter we will learn about using RingZip 56.1 Create Zip File Example : Create myfile.zip contains 4 files load "ziplib.ring" oZip = zip_openfile("myfile.zip",'w') zip_addfile(oZip,"test.c") zip_addfile(oZip,"zip.c") zip_addfile(oZip,"zip.h") zip_addfile(oZip,"miniz.h") zip_close(oZip) 56.2 Extract Zip File Example : Extract myfile.zip to myfolder folder. load "ziplib.ring" zip_extract_allfiles("myfile.zip","myfolder") 56.3 Print Files in Zip file Example : Print file names in the myfile.zip load "ziplib.ring" oZip = zip_openfile("myfile.zip",'r') for x=1 to zip_filescount(oZip) see zip_getfilenamebyindex(oZip,x) + nl next zip_close(oZip) 56.4 Using RingZip Classes The RingZip library comes with two classes. The Zip class and the ZipEntry class. 521
  • 555.
    Ring Documentation, Release1.10 Example (1): load "ziplib.ring" new Zip { setFileName("myfile.zip") open("w") newEntry() { open("test.c") writefile("test.c") close() } close() } Example (2): load "ziplib.ring" new Zip { SetFileName("myfile.zip") Open("w") AddFile("test.c") AddFile("zip.c") AddFile("zip.h") AddFile("miniz.h") Close() } Example (3): load "ziplib.ring" new zip { SetFileName("myfile.zip") ExtractAllFiles("myfolder") } Example (4): load "ziplib.ring" new Zip { SetFileName("myfile.zip") Open("r") see FilesCount() Close() } Example (5): load "ziplib.ring" new Zip { SetFileName("myfile.zip") Open("r") for x = 1 to filescount() See GetFileNameByIndex(x) + nl next Close() 56.4. Using RingZip Classes 522
  • 556.
    Ring Documentation, Release1.10 } 56.5 Zip Class Reference Methods: Method Description/Output SetFileName(cName) Set the Zip file name GetFileName() Return the Zip file name Open(cMode) Open File, cMode = “a”, “w” or “r” Close() Close the Zip File AddFile(cFileName) Add file to the Zip file ExtractAllFiles(cFolder) Extract all files from the Zip file FilesCount() Return files count in the Zip file GetFileNameByIndex(nIndex) Return file name in the Zip file by file index NewEntry() Create new ZipEntry object 56.6 ZipEntry Class Reference Methods: Method Description/Output Open(cFileName) Open new Entry WriteFile(cFileName) Write File to the Entry WriteString(cString) Write String to the Entry Close() Close the Entry 56.5. Zip Class Reference 523
  • 557.
    CHAPTER FIFTYSEVEN 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. 57.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) al_clear_to_color(al_map_rgb(255,0,255)) 524
  • 558.
    Ring Documentation, Release1.10 for x = 1 to 30 bouncer_x += x bouncer_y += x al_set_target_bitmap(al_get_backbuffer(display)) al_clear_to_color(al_map_rgb(0,0,0)) al_draw_bitmap(bouncer, bouncer_x, bouncer_y, 0) al_draw_bitmap(bouncer, 200+bouncer_x,200+ bouncer_y, 0) al_flip_display() al_rest(0.1) next al_clear_to_color(al_map_rgb(255,255,255)) image = al_load_bitmap("man2.jpg") al_draw_bitmap(image,200,200,0) al_flip_display() al_rest(2) 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) FPS = 60 timer = al_create_timer(1.0 / FPS) al_register_event_source(event_queue, al_get_timer_event_source(timer)) al_start_timer(timer) redraw = true SCREEN_W = 640 SCREEN_H = 480 BOUNCER_SIZE = 32 bouncer_x = SCREEN_W / 2.0 - BOUNCER_SIZE / 2.0 bouncer_y = SCREEN_H / 2.0 - BOUNCER_SIZE / 2.0 bouncer_dx = -4.0 bouncer_dy = 4.0 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()) KEY_UP = 1 KEY_DOWN = 2 KEY_LEFT = 3 KEY_RIGHT = 4 Key = [false,false,false,false] 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 57.1. Drawing, Animation and Input 525
  • 559.
    Ring Documentation, Release1.10 # 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 key[KEY_LEFT] = false on ALLEGRO_KEY_RIGHT key[KEY_RIGHT] = false on ALLEGRO_KEY_ESCAPE 57.1. Drawing, Animation and Input 526
  • 560.
    Ring Documentation, Release1.10 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 57.1. Drawing, Animation and Input 527
  • 561.
    Ring Documentation, Release1.10 Then we see two rectangles are moving on the screen 57.1. Drawing, Animation and Input 528
  • 562.
    Ring Documentation, Release1.10 Then we see an image displayed on the screen 57.1. Drawing, Animation and Input 529
  • 563.
    Ring Documentation, Release1.10 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 Keyborad 57.1. Drawing, Animation and Input 530
  • 564.
    Ring Documentation, Release1.10 57.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: 57.2. Using TrueType Fonts 531
  • 565.
    Ring Documentation, Release1.10 57.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) al_destroy_allegro_sample_id(sampleid) 57.3. Playing Sound Files 532
  • 566.
    Ring Documentation, Release1.10 al_destroy_sample(sample) al_destroy_display(display) al_exit() 57.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: 57.4. Scaling and Rotating Images 533
  • 567.
    Ring Documentation, Release1.10 57.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) 57.5. Display Transparent Image 534
  • 568.
    Ring Documentation, Release1.10 Screen Shot: 57.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 cAppName = "Threads Application" 57.6. Using Threads 535
  • 569.
    Ring Documentation, Release1.10 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 Thread(2) : Application Name : Threads Application *****1 *****2 57.6. Using Threads 536
  • 570.
    Ring Documentation, Release1.10 *****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 57.6. Using Threads 537
  • 571.
    CHAPTER FIFTYEIGHT USING RINGLIBSDL In thischapter we will learn about using RingLibSDL to create games based on the LibSDL, SDLImage, SDLTTF and SDLMixer libraries. Tip: RingLibSDL is not distributed with the binary releases for desktop which uses RingAllegro Note: To use RingLibSDL, Check ring/android/ringlibsdl folder. 58.1 Create Window Example: Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN) SDL_Delay(2000) SDL_DestroyWindow(win) SDL_Quit() 58.2 Display Image Example: Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN) ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC ) bmp = SDL_LoadBMP("hello.bmp") tex = SDL_CreateTextureFromSurface(ren,bmp) SDL_FreeSurface(bmp) SDL_RenderClear(ren) SDL_RenderCopy2(ren,tex) SDL_RenderPresent(ren) SDL_Delay(2000) SDL_DestroyTexture(tex) SDL_DestroyRenderer(ren) SDL_DestroyWindow(win) SDL_Quit() 538
  • 572.
    Ring Documentation, Release1.10 58.3 Switch between two images Example: Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN) ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC ) bmp = SDL_LoadBMP("hello.bmp") tex = SDL_CreateTextureFromSurface(ren,bmp) SDL_FreeSurface(bmp) bmp = SDL_LoadBMP("hello2.bmp") tex2 = SDL_CreateTextureFromSurface(ren,bmp) SDL_FreeSurface(bmp) for x = 1 to 10 showtex(tex) showtex(tex2) next SDL_DestroyTexture(tex) SDL_DestroyTexture(tex2) SDL_DestroyRenderer(ren) SDL_DestroyWindow(win) SDL_Quit() func showtex oTex SDL_RenderClear(ren) SDL_RenderCopy2(ren,oTex) SDL_RenderPresent(ren) SDL_Delay(200) 58.4 Draw Rectangle Example: Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN) ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC ) SDL_RenderClear(ren) 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) SDL_RenderPresent(ren) SDL_Delay(2000) SDL_DestroyRenderer(ren) SDL_DestroyWindow(win) SDL_Quit() 58.3. Switch between two images 539
  • 573.
    Ring Documentation, Release1.10 58.5 Display PNG Images Example: Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN) ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC ) bmp = IMG_Load("hello3.png") tex = SDL_CreateTextureFromSurface(ren,bmp) SDL_FreeSurface(bmp) SDL_RenderClear(ren) SDL_RenderCopy2(ren,tex) SDL_RenderPresent(ren) SDL_Delay(2000) SDL_DestroyTexture(tex) SDL_DestroyRenderer(ren) SDL_DestroyWindow(win) SDL_Quit() 58.6 Use TTF Fonts Example: Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN) ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC ) SDL_RenderClear(ren) TTF_Init() font = TTF_OpenFont("pirulen.ttf", 16) color = sdl_new_sdl_color() sdl_set_sdl_color_r(color,0) sdl_set_sdl_color_g(color,255) sdl_set_sdl_color_b(color,0) text = TTF_RenderText_Solid(font,"Welcome to the Ring language",color) surface = SDL_GetWindowSurface(win) SDL_BlitSurface(text, nullpointer(), surface, nullpointer()) SDL_UpdateWindowSurface(win) SDL_Delay(2000) SDL_Destroy_SDL_Color(color) SDL_FreeSurface(text) TTF_CloseFont(font) SDL_DestroyRenderer(ren) SDL_DestroyWindow(win) SDL_Quit() 58.7 Display Transparent Images Example: 58.5. Display PNG Images 540
  • 574.
    Ring Documentation, Release1.10 Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) flags = IMG_INIT_JPG | IMG_INIT_PNG IMG_Init(flags) win = SDL_CreateWindow("Hello World!", 100, 100, 800, 600, SDL_WINDOW_SHOWN) ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC ) bmp = IMG_Load("stars.jpg") tex = SDL_CreateTextureFromSurface(ren,bmp) SDL_FreeSurface(bmp) SDL_RenderClear(ren) SDL_RenderCopy(ren,tex,nullpointer(),nullpointer()) SDL_DestroyTexture(tex) bmp = IMG_Load("player.png") # Image - Set Transparent color (white) myformat = sdl_get_sdl_surface_format(bmp) white = SDL_MapRGB(myformat, 255, 255, 255) SDL_SetColorKey(bmp, SDL_True, white) tex = SDL_CreateTextureFromSurface(ren,bmp) SDL_FreeSurface(bmp) rect = sdl_new_sdl_rect() sdl_set_sdl_rect_x(rect,0) sdl_set_sdl_rect_y(rect,0) sdl_set_sdl_rect_w(rect,100) sdl_set_sdl_rect_h(rect,100) SDL_RenderCopy(ren,tex,nullpointer(),rect) SDL_SetTextureBlendMode(tex,2) SDL_SetTextureAlphaMod(tex,255) sdl_set_sdl_rect_x(rect,200) sdl_set_sdl_rect_y(rect,200) sdl_set_sdl_rect_w(rect,100) sdl_set_sdl_rect_h(rect,100) SDL_RenderCopy(ren,tex,nullpointer(),rect) SDL_DestroyTexture(tex) SDL_Destroy_SDL_Rect(rect) SDL_RenderPresent(ren) SDL_Delay(2000) SDL_DestroyRenderer(ren) SDL_DestroyWindow(win) SDL_Quit() 58.8 Close Window Event Example: Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) 58.8. Close Window Event 541
  • 575.
    Ring Documentation, Release1.10 win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN) myevent = sdl_new_sdl_event() while true thevent = sdl_pollevent(myevent) switch sdl_get_sdl_event_type(myevent) on sdl_get_sdl_quit() exit on sdl_get_sdl_keydown() Key = SDL_GET_SDL_Event_key_keysym_sym(myevent) if key = 27 exit ok off end SDL_DestroyWindow(win) SDL_Quit() 58.9 Mouse Events Example: Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) win = SDL_CreateWindow("Mouse Events ", 100, 100, 640, 480, SDL_WINDOW_SHOWN) TTF_Init() font = TTF_OpenFont("pirulen.ttf", 16) color = sdl_new_sdl_color() sdl_set_sdl_color_r(color,0) sdl_set_sdl_color_g(color,255) sdl_set_sdl_color_b(color,0) surface = SDL_GetWindowSurface(win) myevent = sdl_new_sdl_event() while true cMsg = "" sdl_pollevent(myevent) switch sdl_get_sdl_event_type(myevent) on SDL_QUIT exit on SDL_KEYDOWN Key = SDL_GET_SDL_Event_key_keysym_sym(myevent) if key = 27 exit ok on SDL_MOUSEBUTTONDOWN if sdl_get_Sdl_Event_button_button(myevent) = SDL_BUTTON_LEFT SDL_SETWINDOWTITLE(win, " Button_Left_Down " ) but sdl_get_Sdl_Event_button_button(myevent) = SDL_BUTTON_MIDDLE SDL_SETWINDOWTITLE(win, " Button_Middle_Down " ) but sdl_get_Sdl_Event_button_button(myevent) = SDL_BUTTON_RIGHT SDL_SETWINDOWTITLE(win, " Button_Right_Down " ) ok on SDL_MOUSEMOTION 58.9. Mouse Events 542
  • 576.
    Ring Documentation, Release1.10 sdl_fillrect(surface,nullpointer(),0) if sdl_get_sdl_event_motion_xrel(myevent) < 0 cMsg += " Left " else cMsg += " Right " ok if sdl_get_sdl_event_motion_yrel(myevent) < 0 cMsg += " Up " else cMsg += " Down " ok cMsg += " x = " + sdl_get_sdl_event_motion_x(myevent) cMsg += " y = " + sdl_get_sdl_event_motion_y(myevent) showmsg(cMsg) off end SDL_Destroy_SDL_Color(Color) TTF_CloseFont(font) SDL_DestroyWindow(win) SDL_Quit() func showmsg mymsg text = TTF_RenderText_Solid(font,mymsg,color) SDL_BlitSurface(text, nullpointer(), surface, nullpointer()) SDL_UpdateWindowSurface(win) SDL_FreeSurface(text) 58.10 Play Sound Example: Load "libsdl.ring" SDL_Init(SDL_INIT_EVERYTHING) win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN) Mix_OpenAudio( 44100, MIX_DEFAULT_FORMAT , 2, 10000) Mix_AllocateChannels(4) sound = Mix_LoadWav( "sound.wav" ) Mix_VolumeChunk(sound,1) Mix_PlayChannel(1,sound,0) myevent = sdl_new_sdl_event() while true thevent = sdl_pollevent(myevent) switch sdl_get_sdl_event_type(myevent) on sdl_get_sdl_quit() exit on sdl_get_sdl_keydown() Key = SDL_GET_SDL_Event_key_keysym_sym(myevent) if key = 27 exit ok off end Mix_FreeChunk( sound ) Mix_CloseAudio() 58.10. Play Sound 543
  • 577.
    Ring Documentation, Release1.10 Mix_Quit() SDL_DestroyWindow(win) SDL_Quit() 58.10. Play Sound 544
  • 578.
    CHAPTER FIFTYNINE USING RINGLIBUV In thischapter we will learn about using RingLibuv Note: To use RingLibuv, Check ring/extensions/ringlibuv folder. Information from the library website: http://libuv.org/ Libuv is a multi-platform support library with a focus on asynchronous I/O. Feature highlights • Full-featured event loop backed by epoll, kqueue, IOCP, event ports. • Asynchronous TCP and UDP sockets • Asynchronous DNS resolution • Asynchronous file and file system operations • File system events • ANSI escape code controlled TTY • IPC with socket sharing, using Unix domain sockets or named pipes (Windows) • Child processes • Thread pool • Signal handling • High resolution clock • Threading and synchronization primitives 59.1 First Application using RingLibuv Example: load "libuv.ring" func main myloop = new_uv_loop_t() uv_loop_init(myloop) ? "Now quitting" uv_run(myloop, UV_RUN_DEFAULT) 545
  • 579.
    Ring Documentation, Release1.10 uv_loop_close(myloop) destroy_uv_loop_t(myloop) Output: Now quitting 59.2 The Events Loop Example: load "libuv.ring" counter = 0 idler = NULL func main idler = new_uv_idle_t() uv_idle_init(uv_default_loop(), idler) uv_idle_start(idler, "wait()") ? "Idling..." uv_run(uv_default_loop(), UV_RUN_DEFAULT); uv_loop_close(uv_default_loop()); destroy_uv_idle_t(idler) func wait counter++ if counter >= 100000 uv_idle_stop(idler) ok Output: Idling... 59.3 Server Example Example: load "libuv.ring" ? "Testing RingLibuv - Server Side" DEFAULT_PORT = 13370 DEFAULT_BACKLOG = 1024 addr = new_sockaddr_in() server = NULL client = NULL myloop = NULL func main myloop = uv_default_loop() server = new_uv_tcp_t() 59.2. The Events Loop 546
  • 580.
    Ring Documentation, Release1.10 uv_tcp_init(myloop, server) uv_ip4_addr("127.0.0.1", DEFAULT_PORT, addr) uv_tcp_bind(server, addr, 0) r = uv_listen(server, DEFAULT_BACKLOG, "newconnection()") if r ? "Listen error " + uv_strerror(r) return 1 ok uv_run(myloop, UV_RUN_DEFAULT) destroy_uv_tcp_t(server) destroy_uv_sockaddr_in(addr) func newconnection ? "New Connection" aPara = uv_Eventpara(server,:connect) nStatus = aPara[2] if nStatus < 0 ? "New connection error : " + nStatus return ok client = new_uv_tcp_t() uv_tcp_init(myloop, client) if uv_accept(server, client) = 0 uv_read_start(client, uv_myalloccallback(), "echo_read()") ok func echo_read aPara = uv_Eventpara(client,:read) nRead = aPara[2] buf = aPara[3] if nRead > 0 req = new_uv_write_t() wrbuf = uv_buf_init(get_uv_buf_t_base(buf), nread) uv_write(req, client, wrbuf, 1, "echo_write()") ? uv_buf2str(wrbuf) message = "message from the server to the client" buf = new_uv_buf_t() set_uv_buf_t_len(buf,len(message)) set_uv_buf_t_base(buf,varptr("message","char *")) uv_write(req, client, buf, 1, "echo_write()") ok func echo_write aPara = uv_Eventpara(client,:read) req = aPara[1] Output: When we run the client, We will see the message “New Connection” Then the message “hello from the client” Testing RingLibuv - Server Side New Connection hello from the client 59.3. Server Example 547
  • 581.
    Ring Documentation, Release1.10 59.4 Client Example Example: load "libuv.ring" ? "Testing RingLibuv - Client Side" DEFAULT_PORT = 13370 DEFAULT_BACKLOG = 1024 addr = new_sockaddr_in() connect = NULL buffer = null socket = null func main myloop = uv_default_loop() Socket = new_uv_tcp_t() connect = new_uv_connect_t() uv_tcp_init(myloop, Socket) uv_ip4_addr("127.0.0.1", DEFAULT_PORT, addr) uv_tcp_connect(connect,Socket, addr, "connect()") uv_run(myloop, UV_RUN_DEFAULT) destroy_uv_tcp_t(socket) destroy_uv_connect_t(connect) func connect ? "Client: Start Connection" aPara = uv_Eventpara(connect,:connect) req = aPara[1] nStatus = aPara[2] if nStatus = -1 ? "Error : on_write_end " return ok buf = new_uv_buf_t() message = "hello from the client" set_uv_buf_t_len(buf,len(message)) set_uv_buf_t_base(buf,varptr("message","char *")) tcp = get_uv_connect_t_handle(req) write_req = new_uv_write_t() buf_count = 1 uv_write(write_req, tcp, buf, buf_count, "on_write_end()") func on_write_end uv_read_start(socket, uv_myalloccallback(), "echo_read()") func echo_read aPara = uv_Eventpara(socket,:read) nRead = aPara[2] buf = aPara[3] if nRead > 0 wrbuf = uv_buf_init(get_uv_buf_t_base(buf), nread); ? uv_buf2str(wrbuf) ok Output: 59.4. Client Example 548
  • 582.
    Ring Documentation, Release1.10 We will run the client after the server Testing RingLibuv - Client Side Client: Start Connection hello from the client message from the server to the client 59.5 Server Example Using Classes Example: load "libuv.ring" load "objectslib.ring" ? "Testing RingLibuv - Server Side - Using Classes" open_object(:MyServer) class MyServer from ObjectControllerParent DEFAULT_PORT = 13370 DEFAULT_BACKLOG = 1024 addr = new_sockaddr_in() server = NULL client = NULL myloop = NULL func start myloop = uv_default_loop() server = new_uv_tcp_t() uv_tcp_init(myloop, server) uv_ip4_addr("127.0.0.1", DEFAULT_PORT, addr) uv_tcp_bind(server, addr, 0) r = uv_listen(server, DEFAULT_BACKLOG, Method(:newconnection) ) if r ? "Listen error " + uv_strerror(r) return 1 ok uv_run(myloop, UV_RUN_DEFAULT) destroy_uv_tcp_t(server) destroy_uv_sockaddr_in(addr) func newconnection ? "New Connection" aPara = uv_Eventpara(server,:connect) nStatus = aPara[2] if nStatus < 0 ? "New connection error : " + nStatus return ok client = new_uv_tcp_t() uv_tcp_init(myloop, client) if uv_accept(server, client) = 0 uv_read_start(client, uv_myalloccallback(), Method(:echo_read)) ok 59.5. Server Example Using Classes 549
  • 583.
    Ring Documentation, Release1.10 func echo_read aPara = uv_Eventpara(client,:read) nRead = aPara[2] buf = aPara[3] if nRead > 0 req = new_uv_write_t() wrbuf = uv_buf_init(get_uv_buf_t_base(buf), nread) uv_write(req, client, wrbuf, 1, Method(:echo_write)) ? uv_buf2str(wrbuf) message = "message from the server to the client" buf = new_uv_buf_t() set_uv_buf_t_len(buf,len(message)) set_uv_buf_t_base(buf,varptr("message","char *")) uv_write(req, client, buf, 1, Method(:echo_write)) ok func echo_write aPara = uv_Eventpara(client,:read) req = aPara[1] Output: When we run the client, We will see the message “New Connection” Then the message “hello from the client” Testing RingLibuv - Server Side - Using Classes New Connection hello from the client 59.6 Client Example Using Classes Example: load "libuv.ring" load "objectslib.ring" ? "Testing RingLibuv - Client Side - Using Classes" open_object(:MyClient) Class MyClient from ObjectControllerParent DEFAULT_PORT = 13370 DEFAULT_BACKLOG = 1024 addr = new_sockaddr_in() connect = NULL buffer = null socket = null func start myloop = uv_default_loop() Socket = new_uv_tcp_t() connect = new_uv_connect_t() uv_tcp_init(myloop, Socket) uv_ip4_addr("127.0.0.1", DEFAULT_PORT, addr) 59.6. Client Example Using Classes 550
  • 584.
    Ring Documentation, Release1.10 uv_tcp_connect(connect,Socket, addr, Method(:connect)) uv_run(myloop, UV_RUN_DEFAULT) destroy_uv_tcp_t(socket) destroy_uv_connect_t(connect) func connect ? "Client: Start Connection" aPara = uv_Eventpara(connect,:connect) req = aPara[1] nStatus = aPara[2] if nStatus = -1 ? "Error : on_write_end " return ok buf = new_uv_buf_t() message = "hello from the client" set_uv_buf_t_len(buf,len(message)) set_uv_buf_t_base(buf,varptr("message","char *")) tcp = get_uv_connect_t_handle(req) write_req = new_uv_write_t() buf_count = 1 uv_write(write_req, tcp, buf, buf_count, Method(:on_write_end)) func on_write_end uv_read_start(socket, uv_myalloccallback(), Method(:echo_read)) func echo_read aPara = uv_Eventpara(socket,:read) nRead = aPara[2] buf = aPara[3] if nRead > 0 wrbuf = uv_buf_init(get_uv_buf_t_base(buf), nread); ? uv_buf2str(wrbuf) ok Output: We will run the client after the server Testing RingLibuv - Client Side - Using Classes Client: Start Connection hello from the client message from the server to the client 59.7 Threads Example Example: load "libuv.ring" ? "Testing RingLibuv - Threads" func main one_id = new_uv_thread_t() two_id = new_uv_thread_t() uv_thread_create(one_id, "one()") uv_thread_create(two_id, "two()") 59.7. Threads Example 551
  • 585.
    Ring Documentation, Release1.10 uv_thread_join(one_id) uv_thread_join(two_id) destroy_uv_thread_t(one_id) destroy_uv_thread_t(two_id) func one ? "Message from the First Thread!" func two ? "Message from the Second Thread!" Output: Testing RingLibuv - Threads Message from the First Thread! Message from the Second Thread! 59.8 Threads Example - Using Classes Example: load "libuv.ring" load "objectslib.ring" ? "Testing RingLibuv - Threads - Using Classes" open_object(:MyThreads) class MyThreads from ObjectControllerParent func Start one_id = new_uv_thread_t() two_id = new_uv_thread_t() uv_thread_create(one_id, Method(:One)) uv_thread_create(two_id, Method(:Two)) uv_thread_join(one_id) uv_thread_join(two_id) destroy_uv_thread_t(one_id) destroy_uv_thread_t(two_id) func one ? "Message from the First Thread!" func Two ? "Message from the Second Thread!" Output: Testing RingLibuv - Threads - Using Classes Message from the First Thread! Message from the Second Thread! 59.8. Threads Example - Using Classes 552
  • 586.
    CHAPTER SIXTY 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. 60.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) 60.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 553
  • 587.
    Ring Documentation, Release1.10 60.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/ringlibs/gameengine/gl_allegro.ring • gl_libsdl.ring source code : https://github.com/ring-lang/ring/blob/master/ringlibs/gameengine/gl_libsdl.ring 60.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/ringlibs/gameengine/gameengine.ring 60.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 60.3. Interface to graphics library 554
  • 588.
    Ring Documentation, Release1.10 • 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 60.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. 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. The next table present a group of keywords defined by the class. 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 ot the game objects. 60.7 GameObject Class The next table present the class attributes. 60.6. Game Class 555
  • 589.
    Ring Documentation, Release1.10 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 index of the object in objects list. 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. 60.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. The next table present the class methods. Method Description Draw(oGame) Draw the object 60.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. 60.8. Sprite Class 556
  • 590.
    Ring Documentation, Release1.10 Method Description Draw(oGame) Draw the object 60.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 60.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 60.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 60.10. Animate Class 557
  • 591.
    Ring Documentation, Release1.10 60.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. Screen Shot: 60.14 Using the Game Engine - Drawing Text Load "gameengine.ring" # Give Control to the Game Engine func main # Called by the Game Engine 60.13. Using the Game Engine - Creating the Game Window 558
  • 592.
    Ring Documentation, Release1.10 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: 60.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 60.15. Using the Game Engine - Moving Text 559
  • 593.
    Ring Documentation, Release1.10 { 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 } } # Start the Events Loop Screen Shot: 60.15. Using the Game Engine - Moving Text 560
  • 594.
    Ring Documentation, Release1.10 60.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 60.16. Using the Game Engine - Playing Sound 561
  • 595.
    Ring Documentation, Release1.10 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 60.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 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 60.17. Using the Game Engine - Animation 562
  • 596.
    Ring Documentation, Release1.10 60.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 60.18. Using the Game Engine - Animation and Functions 563
  • 597.
    Ring Documentation, Release1.10 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 } } } } 60.18. Using the Game Engine - Animation and Functions 564
  • 598.
    Ring Documentation, Release1.10 60.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 60.19. Using the Game Engine - Sprite - Automatic Movement using Keyboard 565
  • 599.
    Ring Documentation, Release1.10 60.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 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 60.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 { 60.20. Using the Game Engine - Sprite - Keypress event 566
  • 600.
    Ring Documentation, Release1.10 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 } } } # Start the Events Loop 60.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 { 60.22. Using the Game Engine - Sprite - State event 567
  • 601.
    Ring Documentation, Release1.10 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 } } } } # Start the Events Loop 60.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 60.23. Using the Game Engine - Animate - Events 568
  • 602.
    Ring Documentation, Release1.10 # 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 } } 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: 60.23. Using the Game Engine - Animate - Events 569
  • 603.
    Ring Documentation, Release1.10 60.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], 60.24. Using the Game Engine - Map 570
  • 604.
    Ring Documentation, Release1.10 [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: 60.24. Using the Game Engine - Map 571
  • 605.
    Ring Documentation, Release1.10 60.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], [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 60.25. Using the Game Engine - Map Events 572
  • 606.
    Ring Documentation, Release1.10 Screen Shot: 60.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) 60.26. Using the Game Engine - Object and Drawing 573
  • 607.
    Ring Documentation, Release1.10 next } } 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: 60.26. Using the Game Engine - Object and Drawing 574
  • 608.
    Ring Documentation, Release1.10 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 } } 60.26. Using the Game Engine - Object and Drawing 575
  • 609.
    Ring Documentation, Release1.10 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: 60.27 Stars Fighter Game The Stars Fighter source code 60.27. Stars Fighter Game 576
  • 610.
    Ring Documentation, Release1.10 # 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 size = 16 file = "fonts/pirulen.ttf" text = "(C) 2016, Mahmoud Fayed" x = 45 y=140 } 60.27. Stars Fighter Game 577
  • 611.
    Ring Documentation, Release1.10 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 { file = "images/stars.jpg" x = 0 y = 0 point = -370 direction = ge_direction_dec type = ge_type_background 60.27. Stars Fighter Game 578
  • 612.
    Ring Documentation, Release1.10 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 { type = ge_type_fire file = "images/rocket.png" transparent = true x = oself.x + 30 y = oself.y - 30 width = 30 height = 30 point = -30 60.27. Stars Fighter Game 579
  • 613.
    Ring Documentation, Release1.10 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 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 60.27. Stars Fighter Game 580
  • 614.
    Ring Documentation, Release1.10 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 } } } text { animate = false point = 400 size = 30 file = "fonts/pirulen.ttf" text = "Level : " + oGameState.level x = 500 y=90 } } 60.27. Stars Fighter Game 581
  • 615.
    Ring Documentation, Release1.10 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 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 60.27. Stars Fighter Game 582
  • 616.
    Ring Documentation, Release1.10 } } } 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 startplay=false Screen Shot: 60.27. Stars Fighter Game 583
  • 617.
    Ring Documentation, Release1.10 60.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 while true oGameState = New GameState oGame { 60.28. Flappy Bird 3000 Game 584
  • 618.
    Ring Documentation, Release1.10 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 { animate = false size = 25 file = "fonts/pirulen.ttf" text = "Press Space to start" x = 190 y=470 } text { 60.28. Flappy Bird 3000 Game 585
  • 619.
    Ring Documentation, Release1.10 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 func playstart oGame oGame { FPS = 60 FixedFPS = 120 Title = "Flappy Bird 3000" Sprite { 60.28. Flappy Bird 3000 Game 586
  • 620.
    Ring Documentation, Release1.10 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 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 60.28. Flappy Bird 3000 Game 587
  • 621.
    Ring Documentation, Release1.10 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 } if not oGameState.playerwin oGameState.down -- if oGameState.down = 0 oGameState.down = 3 oself { y += 25 if y > 550 y=550 ok } 60.28. Flappy Bird 3000 Game 588
  • 622.
    Ring Documentation, Release1.10 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], [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 60.28. Flappy Bird 3000 Game 589
  • 623.
    Ring Documentation, Release1.10 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: 60.28. Flappy Bird 3000 Game 590
  • 624.
    Ring Documentation, Release1.10 60.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 { title = "Super Man 2016" 60.29. Super Man 2016 Game 591
  • 625.
    Ring Documentation, Release1.10 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" x = 190 y=470 } 60.29. Super Man 2016 Game 592
  • 626.
    Ring Documentation, Release1.10 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 { FPS = 60 FixedFPS = 15 Title = "Super Man 2016" 60.29. Super Man 2016 Game 593
  • 627.
    Ring Documentation, Release1.10 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 state = func ogame,oself { oself { x-=5 y-=5 60.29. Super Man 2016 Game 594
  • 628.
    Ring Documentation, Release1.10 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" height = 123 dotransparent() y -= 40 oGameState.down = 10 if y<=0 y=0 ok 60.29. Super Man 2016 Game 595
  • 629.
    Ring Documentation, Release1.10 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 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) 60.29. Super Man 2016 Game 596
  • 630.
    Ring Documentation, Release1.10 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 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 60.29. Super Man 2016 Game 597
  • 631.
    Ring Documentation, Release1.10 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 func checkgameover ogame if oGameState.gameresult return ok if oGameState.value <= 0 oGameState.value = 0 oGameState.gameresult = true oGame { 60.29. Super Man 2016 Game 598
  • 632.
    Ring Documentation, Release1.10 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 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 60.29. Super Man 2016 Game 599
  • 633.
    Ring Documentation, Release1.10 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 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" } } 60.29. Super Man 2016 Game 600
  • 634.
    Ring Documentation, Release1.10 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 lastcol = 0 playerwin = false DoorKey = false playerindex = 4 value = 1000 moveplayer = false Screen Shot: 60.29. Super Man 2016 Game 601
  • 635.
    Ring Documentation, Release1.10 60.29. Super Man 2016 Game 602
  • 636.
    CHAPTER SIXTYONE 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. 61.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 61.2 Project Folder Open the project folder : ring/android/ringlibsdl/project 603
  • 637.
    Ring Documentation, Release1.10 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" 61.3 Building the project Move to the ring/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. 61.3. Building the project 604
  • 638.
    Ring Documentation, Release1.10 ant debug 61.3. Building the project 605
  • 639.
    CHAPTER SIXTYTWO USING RINGOPENGL ANDRINGFREEGLUT FOR 3D GRAPHICS In this chapter we will learn about using RingOpenGL 62.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 62.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 606
  • 640.
    Ring Documentation, Release1.10 • 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" 62.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" 62.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 62.3. What is RingFreeGLUT? 607
  • 641.
    Ring Documentation, Release1.10 62.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) glVertex3f(0.0, 0.0, 0.0) 62.5. Drawing using RingOpenGL 608
  • 642.
    Ring Documentation, Release1.10 glVertex3f(0.5, 0.0, 0.0) glVertex3f(0.5, 0.5, 0.0) glVertex3f(0.0, 0.5, 0.0) glEnd() glColor3f(255,0,0) glBegin(GL_POLYGON) glVertex3f(0.0, 0.0, 0.0) glVertex3f(0.5, 0.0, 0.0) glVertex3f(-0.5,- 1, 0.0) glVertex3f(0.0, -1, 0.0) glEnd() glColor3f(0,0,255) glBegin(GL_POLYGON) glVertex3f(0.0, 0.0, 0.0) glVertex3f(-0.5, 0.0, 0.0) glVertex3f(-0.5,- 0.5, 0.0) glVertex3f(0.0, -0.5, 0.0) glEnd() glFlush() Screen Shot 62.5. Drawing using RingOpenGL 609
  • 643.
    Ring Documentation, Release1.10 62.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 62.6. The First Triangle 610
  • 644.
    Ring Documentation, Release1.10 62.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) 62.7. Window Resize Event 611
  • 645.
    Ring Documentation, Release1.10 // Get Back to the Modelview glMatrixMode(GL_MODELVIEW) 62.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 h = glutEventHeight() w = glutEventWidth() 62.8. Triangle Rotation 612
  • 646.
    Ring Documentation, Release1.10 // 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 62.9 Keyboard Events and Colors Example: load "freeglut.ring" load "opengl21lib.ring" 62.9. Keyboard Events and Colors 613
  • 647.
    Ring Documentation, Release1.10 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 glutSwapBuffers(); func changesize h = glutEventHeight() w = glutEventWidth() // Prevent a divide by zero, when window is too short 62.9. Keyboard Events and Colors 614
  • 648.
    Ring Documentation, Release1.10 // (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 62.9. Keyboard Events and Colors 615
  • 649.
    Ring Documentation, Release1.10 62.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) glTranslatef(0.05, 0.10, 0.18) 62.10. The Camera 616
  • 650.
    Ring Documentation, Release1.10 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 glLoadIdentity() // Set the camera 62.10. The Camera 617
  • 651.
    Ring Documentation, Release1.10 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 glutInit() glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA) 62.10. The Camera 618
  • 652.
    Ring Documentation, Release1.10 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 // 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 62.10. The Camera 619
  • 653.
    Ring Documentation, Release1.10 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() // 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) 62.10. The Camera 620
  • 654.
    Ring Documentation, Release1.10 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() next next glutSwapBuffers() func pressKey key = glutEventKey() xx = glutEventX() 62.10. The Camera 621
  • 655.
    Ring Documentation, Release1.10 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 glEnable(GL_DEPTH_TEST) // enter GLUT event processing cycle glutMainLoop() 62.10. The Camera 622
  • 656.
    Ring Documentation, Release1.10 62.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) func drawSnowMan glColor3f(1.0, 1.0, 1.0) // Draw Body glTranslatef(0.0 ,0.75, 0.0) glutSolidSphere(0.75,20,20) 62.11. Mouse Events 623
  • 657.
    Ring Documentation, Release1.10 // 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) 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() 62.11. Mouse Events 624
  • 658.
    Ring Documentation, Release1.10 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 func mouseButton button = glutEventButton() state = glutEventState() xx = glutEventX() yy = glutEventY() // only start motion if the left button is pressed 62.11. Mouse Events 625
  • 659.
    Ring Documentation, Release1.10 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() 62.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 62.12. Menu Events 626
  • 660.
    Ring Documentation, Release1.10 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 // (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) 62.12. Menu Events 627
  • 661.
    Ring Documentation, Release1.10 // 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 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) 62.12. Menu Events 628
  • 662.
    Ring Documentation, Release1.10 // 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() 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() 62.12. Menu Events 629
  • 663.
    Ring Documentation, Release1.10 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) 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 62.12. Menu Events 630
  • 664.
    Ring Documentation, Release1.10 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) off func processShrinkMenu option = glutEventValue() switch option on C_SHRINK scale = 0.5 on C_NORMAL scale = 1.0 off func processColorMenu option = glutEventValue() 62.12. Menu Events 631
  • 665.
    Ring Documentation, Release1.10 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) 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) 62.12. Menu Events 632
  • 666.
    Ring Documentation, Release1.10 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 62.13 Using Fonts Example: 62.13. Using Fonts 633
  • 667.
    Ring Documentation, Release1.10 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 C_INT_GLUT_BITMAP_HELVETICA_18 = 13 func changeSize w = glutEventWidth() 62.13. Using Fonts 634
  • 668.
    Ring Documentation, Release1.10 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) 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)) 62.13. Using Fonts 635
  • 669.
    Ring Documentation, Release1.10 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) // 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() 62.13. Using Fonts 636
  • 670.
    Ring Documentation, Release1.10 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 // ----------------------------------- // 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 62.13. Using Fonts 637
  • 671.
    Ring Documentation, Release1.10 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 // 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() 62.13. Using Fonts 638
  • 672.
    Ring Documentation, Release1.10 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 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) 62.13. Using Fonts 639
  • 673.
    Ring Documentation, Release1.10 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 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 62.13. Using Fonts 640
  • 674.
    Ring Documentation, Release1.10 62.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 62.14. Frames Per Second 641
  • 675.
    Ring Documentation, Release1.10 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 // 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. 62.14. Frames Per Second 642
  • 676.
    Ring Documentation, Release1.10 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 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) 62.14. Frames Per Second 643
  • 677.
    Ring Documentation, Release1.10 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) 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() 62.14. Frames Per Second 644
  • 678.
    Ring Documentation, Release1.10 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() 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 62.14. Frames Per Second 645
  • 679.
    Ring Documentation, Release1.10 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) 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 62.14. Frames Per Second 646
  • 680.
    Ring Documentation, Release1.10 // ----------------------------------- // MENUS // ----------------------------------- 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() 62.14. Frames Per Second 647
  • 681.
    Ring Documentation, Release1.10 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 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 // ----------------------------------- 62.14. Frames Per Second 648
  • 682.
    Ring Documentation, Release1.10 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) 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 62.14. Frames Per Second 649
  • 683.
    Ring Documentation, Release1.10 The Second screen shot 62.15 Make a Cube using RingOpenGL and RingFreeGLUT Example: load "freeglut.ring" load "opengl21lib.ring" // ---------------------------------------------------------- 62.15. Make a Cube using RingOpenGL and RingFreeGLUT 650
  • 684.
    Ring Documentation, Release1.10 // 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 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 62.15. Make a Cube using RingOpenGL and RingFreeGLUT 651
  • 685.
    Ring Documentation, Release1.10 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 // ---------------------------------------------------------- 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() 62.15. Make a Cube using RingOpenGL and RingFreeGLUT 652
  • 686.
    Ring Documentation, Release1.10 // 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: 62.15. Make a Cube using RingOpenGL and RingFreeGLUT 653
  • 687.
    CHAPTER SIXTYTHREE USING RINGOPENGL ANDRINGALLEGRO FOR 3D GRAPHICS In this chapter we will learn about using RingOpenGL and RingAllegro 63.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) 654
  • 688.
    Ring Documentation, Release1.10 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) glTexCoord2f(0.0, 1.0) glVertex3f( 1.0, 1.0, 1.0) glTexCoord2f(0.0, 0.0) glVertex3f( 1.0, -1.0, 1.0) 63.1. 3D Cube and Texture 655
  • 689.
    Ring Documentation, Release1.10 // 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() xrot += 0.3 yrot += 0.2 zrot += 0.4 class GraphicsAppBase display event_queue ev timeout timer redraw = true FPS = 60 SCREEN_W = 800 SCREEN_H = 600 KEY_UP = 1 KEY_DOWN = 2 KEY_LEFT = 3 KEY_RIGHT = 4 Key = [false,false,false,false] TITLE = "Graphics Application" func start SetUp() loadResources() eventsLoop() destroy() func setup al_init() 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, 63.1. 3D Cube and Texture 656
  • 690.
    Ring Documentation, Release1.10 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() end func destroy 63.1. 3D Cube and Texture 657
  • 691.
    Ring Documentation, Release1.10 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: 63.2 Many Cubes 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 63.2. Many Cubes 658
  • 692.
    Ring Documentation, Release1.10 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) 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) 63.2. Many Cubes 659
  • 693.
    Ring Documentation, Release1.10 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) 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 63.2. Many Cubes 660
  • 694.
    Ring Documentation, Release1.10 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 GraphicsAppBase display event_queue ev timeout timer redraw = true FPS = 60 SCREEN_W = 800 SCREEN_H = 600 KEY_UP = 1 KEY_DOWN = 2 KEY_LEFT = 3 KEY_RIGHT = 4 Key = [false,false,false,false] TITLE = "Graphics Application" func start SetUp() loadResources() eventsLoop() destroy() func setup al_init() 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() 63.2. Many Cubes 661
  • 695.
    Ring Documentation, Release1.10 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 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() 63.2. Many Cubes 662
  • 696.
    Ring Documentation, Release1.10 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: 63.2. Many Cubes 663
  • 697.
    Ring Documentation, Release1.10 63.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 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 63.3. TicTacToe 3D Game 664
  • 698.
    Ring Documentation, Release1.10 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] ) 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] 63.3. TicTacToe 3D Game 665
  • 699.
    Ring Documentation, Release1.10 [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 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 63.3. TicTacToe 3D Game 666
  • 700.
    Ring Documentation, Release1.10 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 ] ] 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 //horzintal 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 63.3. TicTacToe 3D Game 667
  • 701.
    Ring Documentation, Release1.10 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 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() 63.3. TicTacToe 3D Game 668
  • 702.
    Ring Documentation, Release1.10 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 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() 63.3. TicTacToe 3D Game 669
  • 703.
    Ring Documentation, Release1.10 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 [ 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) 63.3. TicTacToe 3D Game 670
  • 704.
    Ring Documentation, Release1.10 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 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) 63.3. TicTacToe 3D Game 671
  • 705.
    Ring Documentation, Release1.10 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 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() 63.3. TicTacToe 3D Game 672
  • 706.
    Ring Documentation, Release1.10 func loadresources func drawScene func destroyResources func MouseClickEvent exit # Exit from the Events Loop func CloseEvent exit # Exit from the Events Loop Screen Shot: 63.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 63.4. More 3D Samples 673
  • 707.
    Ring Documentation, Release1.10 The next screen shot for the Camera Sample The next screen shot for the Camera and background sample Developer : Azzeddine Remmal 63.4. More 3D Samples 674
  • 708.
    Ring Documentation, Release1.10 63.4. More 3D Samples 675
  • 709.
    CHAPTER SIXTYFOUR 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 Steam Page (44 Levels) : https://store.steampowered.com/app/939200/Gold_Magic_800/ Ring comes with a Demo Version (21 Levels Only) You will find the game in ring/applications/goldmagic800 folder 64.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. 64.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. 64.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! 676
  • 710.
    Ring Documentation, Release1.10 64.4 Screen Shots We can select the level The next screen shot for level (1) The Gold Magic 800 Level Editor 64.4. Screen Shots 677
  • 711.
    Ring Documentation, Release1.10 64.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. 64.5. Source Code 678
  • 712.
    Ring Documentation, Release1.10 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 64.5. Source Code 679
  • 713.
    CHAPTER SIXTYFIVE DESKTOP AND MOBILEDEVELOPMENT USING RINGQT In this chapter we will learn how to use the Qt framework classes in our Ring applications to create Desktop and Mobile Applications. 65.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()") } btn1 = new qPushButton(win1) { setGeometry(150,200,100,30) settext("Close") setclickevent("pClose()") } lineedit1 = new qLineEdit(win1) { setGeometry(10,100,350,30) } show() } 680
  • 714.
    Ring Documentation, Release1.10 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 65.1. The First GUI Application 681
  • 715.
    Ring Documentation, Release1.10 65.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 stoping 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 65.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) { setGeometry(150,200,100,30) 65.2. The Events Loop 682
  • 716.
    Ring Documentation, Release1.10 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! 65.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) new qtextedit(win1) { setGeometry(10,10,480,480) 65.4. Using the QTextEdit Class 683
  • 717.
    Ring Documentation, Release1.10 } show() } exec() } During the runtime we can paste rich text in the qtextedit widget 65.5 Using the QListWidget Class In this example we will use the QListWidget Class Load "guilib.ring" New qApp { win1 = new qWidget() { 65.5. Using the QListWidget Class 684
  • 718.
    Ring Documentation, Release1.10 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 65.5. Using the QListWidget Class 685
  • 719.
    Ring Documentation, Release1.10 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) settext("Delete item") 65.5. Using the QListWidget Class 686
  • 720.
    Ring Documentation, Release1.10 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 ) } 65.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()) setmodel(ofile) } 65.6. Using QTreeView and QFileSystemModel 687
  • 721.
    Ring Documentation, Release1.10 show() } exec() } The application during the runtime 65.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) layout1 = new qvboxlayout() tree1 = new qtreewidget(win1) { setGeometry(00,00,400,400) 65.7. Using QTreeWidget and QTreeWidgetItem 688
  • 722.
    Ring Documentation, Release1.10 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 65.7. Using QTreeWidget and QTreeWidgetItem 689
  • 723.
    Ring Documentation, Release1.10 65.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 65.8. Using QComboBox Class 690
  • 724.
    Ring Documentation, Release1.10 65.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") } 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") } 65.9. Creating Menubar 691
  • 725.
    Ring Documentation, Release1.10 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) { settext("About") } addaction(oAction) } } show() } exec() } The application during the runtime 65.9. Creating Menubar 692
  • 726.
    Ring Documentation, Release1.10 65.10 Context Menu Example: load "guilib.ring" new qApp { win = new qwidget() { setwindowtitle("Context Menu") resize(400,400) myfilter = new qAllEvents(win) { setContextmenuEvent("mymenu()") } installeventfilter(myfilter) show() } exec() } func mymenu new qMenu(win) { oAction = new qAction(win) { settext("new") SetCLickevent("See :New") 65.10. Context Menu 693
  • 727.
    Ring Documentation, Release1.10 } 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()) } 65.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") 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() } 65.11. Creating Toolbar 694
  • 728.
    Ring Documentation, Release1.10 The application during the runtime 65.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() } 65.12. Creating StatusBar 695
  • 729.
    Ring Documentation, Release1.10 The application during the runtime 65.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) { 65.13. Using QDockWidget 696
  • 730.
    Ring Documentation, Release1.10 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 65.14 Using QTabWidget In this example we will learn about using the QTabWidget class Load "guilib.ring" New qApp { 65.14. Using QTabWidget 697
  • 731.
    Ring Documentation, Release1.10 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") } } 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 65.14. Using QTabWidget 698
  • 732.
    Ring Documentation, Release1.10 65.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() } 65.15. Using QTableWidget 699
  • 733.
    Ring Documentation, Release1.10 exec() } The application during the runtime 65.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 65.16. Using QProgressBar 700
  • 734.
    Ring Documentation, Release1.10 65.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() } exec() } The application during the runtime 65.17. Using QSpinBox 701
  • 735.
    Ring Documentation, Release1.10 65.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() } exec() } The application during the runtime 65.18. Using QSlider 702
  • 736.
    Ring Documentation, Release1.10 65.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() } The application during the runtime 65.19. Using QDateEdit 703
  • 737.
    Ring Documentation, Release1.10 65.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 65.20. Using QDial 704
  • 738.
    Ring Documentation, Release1.10 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()") } pdial = new qdial(win1) { 65.20. Using QDial 705
  • 739.
    Ring Documentation, Release1.10 setGeometry(100,50,250,300) setNotchesVisible(true) setValue(50) SetValueChangedEvent("pDialMove()") } lineedit1 = new qlineedit(win1) { setGeometry(200,400,50,30) setalignment(Qt_AlignHCenter) settext(string(pdial.value())) setreturnPressedEvent("pPress()") } show() } exec() } func pIncrement pdial{val=value()} pdial.setvalue(val+1) lineedit1{settext(string(val+1))} func pDecrement pdial{val=value()} pdial.setvalue(val-1) lineedit1{settext(string(val-1))} func pPress lineedit1{val=text()} pdial.setvalue(number(val)) func pDialMove lineedit1.settext(""+pdial.value()) 65.20. Using QDial 706
  • 740.
    Ring Documentation, Release1.10 65.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() } The application during the runtime 65.21. Using QWebView 707
  • 741.
    Ring Documentation, Release1.10 65.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 65.22. Using QCheckBox 708
  • 742.
    Ring Documentation, Release1.10 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 65.23 Using QRadioButton and QButtonGroup In this example we will learn about using the QRadioButton and QButtonGroup classes Load "guilib.ring" 65.23. Using QRadioButton and QButtonGroup 709
  • 743.
    Ring Documentation, Release1.10 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 65.23. Using QRadioButton and QButtonGroup 710
  • 744.
    Ring Documentation, Release1.10 65.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 65.24. Adding Hyperlink to QLabel 711
  • 745.
    Ring Documentation, Release1.10 65.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") } videowidget4 = new qvideowidget(win1) { 65.25. QVideoWidget and QMediaPlayer 712
  • 746.
    Ring Documentation, Release1.10 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 65.25. QVideoWidget and QMediaPlayer 713
  • 747.
    Ring Documentation, Release1.10 65.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 65.26. Using QFrame 714
  • 748.
    Ring Documentation, Release1.10 65.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()) } 65.27. Display Image using QLabel 715
  • 749.
    Ring Documentation, Release1.10 showMaximized() } exec() } The application during the runtime 65.28 Menubar and StyleSheet Example In this example we will learn about creating menubar and setting the window stylesheet Load "guilib.ring" New qApp { 65.28. Menubar and StyleSheet Example 716
  • 750.
    Ring Documentation, Release1.10 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() } The application during the runtime 65.28. Menubar and StyleSheet Example 717
  • 751.
    Ring Documentation, Release1.10 65.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()") } lineedit1 = new qlineedit(win1) { setGeometry(10,100,350,30) settextchangedevent("pChange()") setreturnpressedevent("penter()") } 65.29. QLineEdit Events and QMessageBox 718
  • 752.
    Ring Documentation, Release1.10 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 65.29. QLineEdit Events and QMessageBox 719
  • 753.
    Ring Documentation, Release1.10 65.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() } 65.30. Other Widgets Events 720
  • 754.
    Ring Documentation, Release1.10 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 65.30. Other Widgets Events 721
  • 755.
    Ring Documentation, Release1.10 65.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 65.31. Using the QTimer Class 722
  • 756.
    Ring Documentation, Release1.10 65.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 BarMan{ setvalue(value() + Increment) } 65.32. Using QProgressBar and Timer 723
  • 757.
    Ring Documentation, Release1.10 Func theTime return "Time : " + Time() 65.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)) PosLeft = (BoxWidth - imageW ) / 2 PosTop = (BoxHeight - imageH ) / 2 65.33. Display Scaled Image using QLabel 724
  • 758.
    Ring Documentation, Release1.10 setGeometry(PosLeft,PosTop,imageW,imageH) } TimerMan = new qtimer(win1) { setinterval(100) ### interval 100 millisecs. settimeoutevent("pTime()") ### ==>> func start() } show() } exec() } ###------------------------------------------------------ ### Fuction 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) 65.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) settext("open file") setclickevent("pOpen()") } show() } 65.34. Using the QFileDialog Class 725
  • 759.
    Ring Documentation, Release1.10 exec() } Func pOpen new qfiledialog(win1) { cName = getopenfilename(win1,"open file","c:","source files(*.ring)") win1.setwindowtitle(cName) } The application during the runtime 65.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) { setgeometry(200,400,100,30) settext("draw") setclickevent("draw()") } show() } 65.35. Drawing using QPainter 726
  • 760.
    Ring Documentation, Release1.10 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 65.35. Drawing using QPainter 727
  • 761.
    Ring Documentation, Release1.10 65.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()") } showmaximized() 65.36. Printing using QPrinter 728
  • 762.
    Ring Documentation, Release1.10 } 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) myweb.show() } system ("test.pdf") system ("test2.pdf") 65.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 printer1 { painter = new qpainter() { 65.37. Using QPrintPreviewDialog 729
  • 763.
    Ring Documentation, Release1.10 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: 65.37. Using QPrintPreviewDialog 730
  • 764.
    Ring Documentation, Release1.10 65.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() { 65.38. Creating More than one Window 731
  • 765.
    Ring Documentation, Release1.10 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 65.39 Playing Sound Example: 65.39. Playing Sound 732
  • 766.
    Ring Documentation, Release1.10 Load "guilib.ring" new qapp { win1 = new qwidget() { setwindowtitle("play sound!") show() } new qmediaplayer() { setmedia(new qurl("footstep.wav")) setvolume(50) play() } exec() } 65.40 Using the QColorDialog Class Example: Load "guilib.ring" oApp = new myapp { start() } Class MyApp oColor win1 Func start 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 65.40. Using the QColorDialog Class 733
  • 767.
    Ring Documentation, Release1.10 65.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() } 65.41. Using qLCDNumber Class 734
  • 768.
    Ring Documentation, Release1.10 The application during the runtime 65.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 65.42. Movable Label Example 735
  • 769.
    Ring Documentation, Release1.10 65.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 65.43. QMessagebox Example 736
  • 770.
    Ring Documentation, Release1.10 65.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") lcheck = exec() 65.44. Using QInputDialog Class 737
  • 771.
    Ring Documentation, Release1.10 if lCheck win1.setwindowtitle(oInput.textvalue()) ok } The application during the runtime 65.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 { SetDialogIcon("notepad.png") msginfo(:Ring,:Welcome) see confirmMsg(:Ring,"Are you sure?") + nl 65.45. Dialog Functions 738
  • 772.
    Ring Documentation, Release1.10 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 } 65.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 65.46. KeyPress and Mouse Move Events 739
  • 773.
    Ring Documentation, Release1.10 65.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()") myfilter.setLeaveevent("pLeave()") 65.47. Moving Objects using the Mouse 740
  • 774.
    Ring Documentation, Release1.10 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 65.47. Moving Objects using the Mouse 741
  • 775.
    Ring Documentation, Release1.10 65.47. Moving Objects using the Mouse 742
  • 776.
    Ring Documentation, Release1.10 65.47. Moving Objects using the Mouse 743
  • 777.
    Ring Documentation, Release1.10 65.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 65.48. Inheritance from GUI Classes 744
  • 778.
    Ring Documentation, Release1.10 65.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 oDesktop = new qDesktopWidget() 65.49. Using QDesktopWidget Class 745
  • 779.
    Ring Documentation, Release1.10 oRect = oDesktop.screenGeometry( oDesktop.primaryScreen() ) win1.move((oRect.width()-win1.width()) /2 , (oRect.Height()-win1.Height())/2 ) win1.show() The application during the runtime 65.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) } new qtimer(win1) { setinterval(50) 65.50. Rotate Text 746
  • 780.
    Ring Documentation, Release1.10 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 65.50. Rotate Text 747
  • 781.
    Ring Documentation, Release1.10 65.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) } setLayout(Layout1) 65.51. Change Focus 748
  • 782.
    Ring Documentation, Release1.10 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 65.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 see "(" + match.capturedStart(1) + "," + match.capturedEnd(1)+ ")" + nl see "(" + match.capturedStart(2) + "," + match.capturedEnd(2)+ ")" + nl see "(" + match.capturedStart(3) + "," + match.capturedEnd(3)+ ")" + nl 65.52. Regular Expressions 749
  • 783.
    Ring Documentation, Release1.10 } } Output Using Regular Expressions dd w+ 1 0 1 11 one ^(dd)/(dd)/(dddd)$ 1 08 12 1985 (0,2) (3,5) (6,10) 65.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()") } lineedit1 = new qtextedit(win1) { setGeometry(150,50,200,300) } win1 { setwindowtitle("client") setgeometry(10,100,400,400) show() 65.53. Simple Client and Server Example 750
  • 784.
    Ring Documentation, Release1.10 } 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) } cOutput = "Server Started" + nl + "listen to port 9999" + nl lineedit1.settext(cOutput) Func pNewConnection oTcpClient = oTcpServer.nextPendingConnection() 65.53. Simple Client and Server Example 751
  • 785.
    Ring Documentation, Release1.10 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 65.54 Dynamic Objects We may create objects in the runtime and add them to windows. Example: load "guilib.ring" oFormDesigner = new FormDesigner { start("oFormDesigner") } Class FormDesigner winToolBox winForm aObjects = [] func start cObjectName oApp = new qApp winToolBox = new qWidget() winToolBox.setWindowTitle("ToolBox") 65.54. Dynamic Objects 752
  • 786.
    Ring Documentation, Release1.10 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 65.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 65.55. Weight History Application 753
  • 787.
    Ring Documentation, Release1.10 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) } 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() } 65.55. Weight History Application 754
  • 788.
    Ring Documentation, Release1.10 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) 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) 65.55. Weight History Application 755
  • 789.
    Ring Documentation, Release1.10 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] 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 65.55. Weight History Application 756
  • 790.
    Ring Documentation, Release1.10 65.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" 65.56. Notepad Application 757
  • 791.
    Ring Documentation, Release1.10 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) { 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") 65.56. Notepad Application 758
  • 792.
    Ring Documentation, Release1.10 } , 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()") } 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()") 65.56. Notepad Application 759
  • 793.
    Ring Documentation, Release1.10 } 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() 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()") 65.56. Notepad Application 760
  • 794.
    Ring Documentation, Release1.10 } 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")) 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") 65.56. Notepad Application 761
  • 795.
    Ring Documentation, Release1.10 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) } } 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() 65.56. Notepad Application 762
  • 796.
    Ring Documentation, Release1.10 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) { 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) { 65.56. Notepad Application 763
  • 797.
    Ring Documentation, Release1.10 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() 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 65.56. Notepad Application 764
  • 798.
    Ring Documentation, Release1.10 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) { 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) { 65.56. Notepad Application 765
  • 799.
    Ring Documentation, Release1.10 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") 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() 65.56. Notepad Application 766
  • 800.
    Ring Documentation, Release1.10 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 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") 65.56. Notepad Application 767
  • 801.
    Ring Documentation, Release1.10 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 new qfiledialog(win1) { cName = getsavefilename(win1,"Save As","","source files(*.ring)") if cName != NULL cActiveFileName = cName writefile(cActiveFileName,textedit1.toplaintext()) status1.showmessage("File : " + cActiveFileName + " saved!",0) pSetActiveFileName() lAskToSave = false ok } func pPrint status1.showmessage("Printing to File : RingDoc.pdf",0) printer1 = new qPrinter(0) { setoutputformat(1) # 1 = pdf setoutputfilename("RingDoc.pdf") textedit1.print(printer1) } status1.showmessage("Done!",0) system("RingDoc.pdf") func pCut textedit1.cut() 65.56. Notepad Application 768
  • 802.
    Ring Documentation, Release1.10 status1.showmessage("Cut!",0) func pCopy textedit1.copy() status1.showmessage("Copy!",0) func pPaste textedit1.paste() status1.showmessage("Paste!",0) func pFont oFontDialog = new qfontdialog() { aFont = getfont() } textedit1.selectall() cFont = aFont[1] pSetFont() Func pSetFont myfont = new qfont("",0,0,0) myfont.fromstring(cFont) textedit1.setcurrentfont(myfont) Func pColor new qcolordialog() { aTextColor = GetColor() } pSetColors() Func pColor2 new qcolordialog() { aBackColor = GetColor() } pSetColors() Func pSetColors textedit1.setstylesheet("color: rgb(" + aTextColor[1] + "," + aTextColor[2] + "," + aTextColor[3] + ");" + "background-color: rgb(" + 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 65.56. Notepad Application 769
  • 803.
    Ring Documentation, Release1.10 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 + "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)) } 65.56. Notepad Application 770
  • 804.
    Ring Documentation, Release1.10 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 The next window for “search and replace” The next screen shot demonstrates the application main window 65.56. Notepad Application 771
  • 805.
    Ring Documentation, Release1.10 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. 65.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) next next 65.57. The Cards Game 772
  • 806.
    Ring Documentation, Release1.10 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 ; background-color: black ;") setclickevent("Page1.win1.close()") } 65.57. The Cards Game 773
  • 807.
    Ring Documentation, Release1.10 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 aStatus[x] = 1 aStatusValues[x] = aValues[nPos] del(aValues,nPos) Player1Eat(x,aStatusValues[x]) checknewgame() 65.57. The Cards Game 774
  • 808.
    Ring Documentation, Release1.10 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 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 65.57. The Cards Game 775
  • 809.
    Ring Documentation, Release1.10 (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 oTest = new qTest oTest.qsleep(nTime) The application during the runtime 65.57. The Cards Game 776
  • 810.
    Ring Documentation, Release1.10 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) 65.57. The Cards Game 777
  • 811.
    Ring Documentation, Release1.10 Note: using Qt we can run the same application on other Mobile systems 65.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() SetRedoAvailableEvent() Continued on next page 65.58. Classes and their Methods to use the default events 778
  • 812.
    Ring Documentation, Release1.10 Table 65.1 – continued from previous page Class Name Methods to use the default Events 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() SetCellDoubleClickedEvent() Continued on next page 65.58. Classes and their Methods to use the default events 779
  • 813.
    Ring Documentation, Release1.10 Table 65.1 – continued from previous page Class Name Methods to use the default Events 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() QTimer SetTimeoutEvent() Continued on next page 65.58. Classes and their Methods to use the default events 780
  • 814.
    Ring Documentation, Release1.10 Table 65.1 – continued from previous page Class Name Methods to use the default Events 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() 65.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. 65.59. Methods to use Events with Events Filter 781
  • 815.
    Ring Documentation, Release1.10 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) 65.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 65.60. The Difference between Qt and RingQt 782
  • 816.
    Ring Documentation, Release1.10 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 65.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. 65.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/applications/formdesigner/tests/indexstart/indexstartView.ring 2. https://github.com/ring-lang/ring/blob/master/applications/formdesigner/tests/indexstart/indexstartController.ring 65.61. RingQt Classes and their Qt Documentation 783
  • 817.
    Ring Documentation, Release1.10 65.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 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 { TD { text("Test" ) } TD { text("30" ) } TD { text("Egypt" ) } 65.63. Creating Reports using the WebLib and the GUILib 784
  • 818.
    Ring Documentation, Release1.10 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) web.show() } system ("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: 65.63. Creating Reports using the WebLib and the GUILib 785
  • 819.
    Ring Documentation, Release1.10 65.63. Creating Reports using the WebLib and the GUILib 786
  • 820.
    CHAPTER SIXTYSIX BUILDING RINGQT APPLICATIONSFOR MOBILE In this chapter we will learn about Building RingQt Applications for Mobile. 66.1 Download Requirements Check the next link : http://doc.qt.io/qt-5/androidgs.html Download • 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 66.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 : B:mahmoudToolsJava-Androidadt-bundle-windows-x86-20140702sdk 787
  • 821.
    Ring Documentation, Release1.10 66.3 Install Qt for Android • You can install Qt for Android from the next link https://download.qt.io/archive/qt/5.5/5.5.1/ • Run Qt Creator, Select Tools > Options > Android to add the Android NDK and SDK paths. http://doc.qt.io/qtcreator/creator-developing-android.html 66.4 Using Ring2EXE Starting from Ring 1.6 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 66.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 66.3. Install Qt for Android 788
  • 822.
    Ring Documentation, Release1.10 66.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: 66.6. Comments about developing for Android using RingQt 789
  • 823.
    Ring Documentation, Release1.10 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. 66.6. Comments about developing for Android using RingQt 790
  • 824.
    CHAPTER SIXTYSEVEN OBJECTS LIBRARY FORRINGQT APPLICATION In this chapter we will learn about the objects library for RingQt applications. Ring comes with the Objects library for RingQt applications. Instead of using global variables for windows objects and connecting events to objects using the object name, the Objects Library will manage the GUI objects and will provide a more natural API to quickly create one or many windows from the same class and the 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. The Objects Library is designed to be used with the MVC Design Pattern. The Objects Library is merged in RingQt so you can use it directly when you use RingQt 67.1 Library Usage • Use the Open_Window(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 Last_Window() 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 Open_Window() It will be called. • In the view class, Define the GUI window object as an attribute called win. • You can use Open_WindowNoShow() to avoid displaying the window. • You can use Open_WindowAndLink() to quickly get methods to access the windows. 67.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. 791
  • 825.
    Ring Documentation, Release1.10 • 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 { open_window( :MainWindowController ) exec() } class MainWindowController from WindowsControllerParent oView = new MainWindowView func SubWindowAction Open_window( :SubWindowController ) Last_Window().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 ) ) } resize(400,400) } The next screen shot after creating three sub windows. 67.2. Example 792
  • 826.
    Ring Documentation, Release1.10 The next screen shot after clicking on the button in each sub window. 67.2. Example 793
  • 827.
    Ring Documentation, Release1.10 67.3 Open_WindowAndLink() Function We can use the Open_WindowAndLink() 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/applications/formdesigner/tests/twowindowspart5/firstwindowView.ring 2. https://github.com/ring-lang/ring/blob/master/applications/formdesigner/tests/twowindowspart5/firstwindowController.ring Second Window 1. https://github.com/ring-lang/ring/blob/master/applications/formdesigner/tests/twowindowspart5/secondwindowView.ring 2. https://github.com/ring-lang/ring/blob/master/applications/formdesigner/tests/twowindowspart5/secondwindowController.ring 67.3. Open_WindowAndLink() Function 794
  • 828.
    Ring Documentation, Release1.10 In the next code for example (from FirstWindowController.ring) The Open_WindowAndLink() will create an object from the SecondWindowController Class Then will add the Method : SecondWindow(), IsSecondWindow() Methods to the FirstWindowController Class Also will add the Method : FirstWindow(), 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 Last_Window(), Parent() and SetParentObject() methods. class firstwindowController from windowsControllerParent oView = new firstwindowView func OpenSecondWindow Open_WindowAndLink(:SecondWindowController,self) func SendMessage if IsSecondWindow() SecondWindow().setMessage("Message from the first window") ok func setMessage cMessage oView.Label1.setText(cMessage) 67.4 Open_WindowInPackages() Function The Open_WindowInPackages() function is the same as Open_Window() but takes an extra list that determine the packages to import before opening the window. Syntax: Open_WindowInPackages(cClassName,aPackagesList) Example: The next example from the Form Designer source code, Open the Window Flags window using the open_windowInPackages() function. We determine the class name “WindowFlagsController” and the packages name. The Window Flags window uses the FormDesigner and System.GUI packages. open_windowInPackages(:WindowFlagsController,[ "formdesigner", "System.GUI" ]) 67.5 Objects Library Source Code The library source code is very simple, You can check the source code files • https://github.com/ring-lang/ring/blob/master/extensions/ringqt/objectslib/objects.ring • https://github.com/ring-lang/ring/blob/master/extensions/ringqt/objectslib/subwindows.ring 67.4. Open_WindowInPackages() Function 795
  • 829.
    CHAPTER SIXTYEIGHT 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. 796
  • 830.
    Ring Documentation, Release1.10 68.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. 68.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. 68.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 68.1. The Designer Windows 797
  • 831.
    Ring Documentation, Release1.10 68.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. 68.5 Events Code 1. Just type the method name in the event property. 68.4. Running Forms 798
  • 832.
    Ring Documentation, Release1.10 (2) Then write the method code in the controller class. 68.5. Events Code 799
  • 833.
    Ring Documentation, Release1.10 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 : 68.5. Events Code 800
  • 834.
    Ring Documentation, Release1.10 The Event Code func SayHello oView { LineEdit2.setText("Hello "+ LineEdit1.text() ) } 68.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. 68.7 Menubar Designer From the Window properties we can open the Menubar Designer 68.6. Keyboard Shortcuts 801
  • 835.
    Ring Documentation, Release1.10 68.8 Window Flags From the Window properties we can open the Window Flags window. 68.8. Window Flags 802
  • 836.
    Ring Documentation, Release1.10 68.9 Entering Items For some controls like the List Widget we can enter items separated by comma ‘,’ 68.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. 68.11 More Samples and Tests Check the folder : ring/applications/formdesigner/tests Online : https://github.com/ring-lang/ring/tree/master/applications/formdesigner/tests 68.9. Entering Items 803
  • 837.
    CHAPTER SIXTYNINE MULTI-LANGUAGE APPLICATIONS There aremany ways to create multi-language Ring application! In this chapter we will learn about using the String2Constant tool 69.1 Using String2Constant Starting from Ring 1.8 we have the String2Constant application You will find this tool in the ring/samples/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. 804
  • 838.
    Ring Documentation, Release1.10 69.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/formdesinger/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 69.2. Form Designer Translation 805
  • 839.
    Ring Documentation, Release1.10 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. 69.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 69.3. Forms Translation 806
  • 840.
    Ring Documentation, Release1.10 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) } 69.3. Forms Translation 807
  • 841.
    CHAPTER SEVENTY 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 70.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 70.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 808
  • 842.
    Ring Documentation, Release1.10 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 attibutes 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. 70.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). 70.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. 70.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 :- • Global Scope —> Global Scope • Object Scope —> Object Scope 70.3. How Ring find the variable? 809
  • 843.
    Ring Documentation, Release1.10 • 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. 70.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. 70.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 address phone Solution (2) - Use special mark for global variable names like $ 70.6. How Ring Define Variables and Attributes 810
  • 844.
    Ring Documentation, Release1.10 $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() 70.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 70.8. Conflict between Class Attributes and Local Variables 811
  • 845.
    Ring Documentation, Release1.10 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 70.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 ! 70.9. Using Braces to access objects inside Class Methods 812
  • 846.
    Ring Documentation, Release1.10 } 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 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). 70.9. Using Braces to access objects inside Class Methods 813
  • 847.
    Ring Documentation, Release1.10 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 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. 70.9. Using Braces to access objects inside Class Methods 814
  • 848.
    Ring Documentation, Release1.10 70.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 insead 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. 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. 70.10. Accessing the class attributes from braces inside class methods 815
  • 849.
    Ring Documentation, Release1.10 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. 70.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" 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()") } 70.11. Creating a Class for each Window in GUI applications 816
  • 850.
    Ring Documentation, Release1.10 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 ) ) } 70.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 —> Gloabl 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" 70.12. Conflict between self inside braces and self in the class region 817
  • 851.
    Ring Documentation, Release1.10 } 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 attribue 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 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 70.12. Conflict between self inside braces and self in the class region 818
  • 852.
    Ring Documentation, Release1.10 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 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 { 70.12. Conflict between self inside braces and self in the class region 819
  • 853.
    Ring Documentation, Release1.10 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 70.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 70.13. Using braces to escape from the current object scope 820
  • 854.
    Ring Documentation, Release1.10 z: 30.000000 x: 10.000000 y: 20.000000 z: 30.000000 100 200 300 100 200 300 10 20 30 70.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 70.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 70.14. The For Loops uses the local scope 821
  • 855.
    Ring Documentation, Release1.10 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. 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 70.15. Summary of Scope Rules 822
  • 856.
    Ring Documentation, Release1.10 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 { } , 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. 70.15. Summary of Scope Rules 823
  • 857.
    CHAPTER SEVENTYONE 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 71.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. 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. 824
  • 858.
    Ring Documentation, Release1.10 71.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() f2() f3() } myline() Output: 71.2. Example about Sharing Names between Functions and Methods 825
  • 859.
    Ring Documentation, Release1.10 ======================================== 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 ======================================== 71.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 Class myclass func test myline() see "test method" + nl f1() f2() f3() # call f3() method new local { f3() } # call f3() function myline() 71.3. Calling a function sharing the name with a method in the current class 826
  • 860.
    Ring Documentation, Release1.10 func f3 see "f3 method" + nl class local Output: ======================================== test method f1 function f2 function f3 method f3 function ======================================== 71.3. Calling a function sharing the name with a method in the current class 827
  • 861.
    CHAPTER SEVENTYTWO SYNTAX FLEXIBILITY In thischapter we will learn about some options that are provided automatically by the Ring compiler for syntax flexibility. 72.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 print "number three" + nl endif endfor 828
  • 862.
    Ring Documentation, Release1.10 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 72.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 changeringoperator plus + changeringkeyword PRINT SEE 72.2. Change Language Operators 829
  • 863.
    Ring Documentation, Release1.10 72.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 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 72.3. Load Syntax Files 830
  • 864.
    Ring Documentation, Release1.10 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. 72.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 72.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: 72.4. Using “()” around the function parameters 831
  • 865.
    Ring Documentation, Release1.10 Hello How are you? Welcome to Ring one two three 72.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 72.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 72.6. Using $ and @ in the start of the variable name 832
  • 866.
    Ring Documentation, Release1.10 72.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 72.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: 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 72.8. Using the ‘else’ keyword as ‘other’ in switch statement 833
  • 867.
    Ring Documentation, Release1.10 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 72.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: 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 { 72.10. Using braces to start and end different control structures 834
  • 868.
    Ring Documentation, Release1.10 x = 1 / 0 catch see "catching error" + nl } Output: if statement.. one for loop.. 12345678910 switch... one try catch... catching error 72.11 Using ‘put’ and ‘get’ as ‘see’ and ‘give’ We can replace the ‘see’ keyword with the ‘put’ keyword. Also we can replacew the ‘give’ keyword with the ‘get’ keyword. Example: put "Hello World" + nl put "Enter Your Name ? " Get Name Put "Hello " + Name 72.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 "thre" + 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 "thre" + nl else put "else" + nl } } 72.11. Using ‘put’ and ‘get’ as ‘see’ and ‘give’ 835
  • 869.
    Ring Documentation, Release1.10 72.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 72.14 Using braces { } in Packages/Classes/Functions Example: load "stdlib.ring" import mypackage new myclass { myfunc() } package mypackage { class myclass { func myfunc { print("Hello, World!n") } } } 72.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 72.13. Using ‘def’ as ‘func’ in functions/methods definition 836
  • 870.
    Ring Documentation, Release1.10 72.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 72.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 72.16. Using ‘endpackage’/’endclass’/’endfunc’ keywords after Packages/Classes/Functions 837
  • 871.
    CHAPTER SEVENTYTHREE INTRODUCTION TO THETYPE HINTS LIBRARY In this chapter we will learn about the Type Hints Library 73.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. 73.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 ; } 73.3 User Types The Type Hints library is very powerful and will support user types (Classes) automatically Example: load "typehints.ring" import mypackage 838
  • 872.
    Ring Documentation, Release1.10 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 } } } 73.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 ; } 73.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 73.4. Using Types inside Code 839
  • 873.
    Ring Documentation, Release1.10 double void # High Level Types string list number object # Other public static abstract protected override 73.5. Rules 840
  • 874.
    CHAPTER SEVENTYFOUR 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 -w Display Warnings 74.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: =================================================== Tokens - Generated by the Scanner =================================================== 841
  • 875.
    Ring Documentation, Release1.10 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 Keyword : CLASS Identifier : point Identifier : x Identifier : y Identifier : z 74.1. Printing Tokens 842
  • 876.
    Ring Documentation, Release1.10 EndLine =================================================== 74.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 Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Factor --> Number Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic 74.2. Printing Rules 843
  • 877.
    Ring Documentation, Release1.10 Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> 'For' Identifier '=' Expr to Expr ['step' Expr] Line 4 Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus] 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 5 Rule : Next --> 'Next' Line 6 Rule : Mixer -> '(' [Expr { ',' Expr} ] ')' Line 8 Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus] Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> Expr Rule : Statement --> 'Func' Identifier [ParaList] Line 9 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 74.2. Printing Rules 844
  • 878.
    Ring Documentation, Release1.10 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 10 Rule : Factor --> New Identifier {'.' Identifier } Rule : Mixer --> '{' {Statement} BraceEnd Rule : Factor --> Number Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Assignment -> '=' Expr Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus] Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> Expr Rule : Factor --> Number Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Assignment -> '=' Expr Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus] Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot 74.2. Printing Rules 845
  • 879.
    Ring Documentation, Release1.10 Rule : Expr --> LogicNot Rule : Statement --> Expr Rule : Factor --> Number Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Assignment -> '=' Expr Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus] Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> Expr Rule : BraceEnd --> '}' Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Assignment -> '=' Expr Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus] Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> Expr Line 11 Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus] Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift 74.2. Printing Rules 846
  • 880.
    Ring Documentation, Release1.10 Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> 'See' Expr Line 13 Rule : Statement --> 'Class' Identifier Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus] Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> Expr Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus] Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> Expr Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus] Rule : Range --> Factor Rule : Term --> Range Rule : Arithmetic --> Term Rule : BitShift --> Arithmetic Rule : BitAnd --> BitShift Rule : BitOrXOR --> BitAnd Rule : Compare --> BitOrXOR Rule : EqualOrNot --> Compare Rule : LogicNot -> EqualOrNot Rule : Expr --> LogicNot Rule : Statement --> Expr =================================================== 74.3 Printing Intermediate Code Command: ring test.ring -ic -norun Output: 74.3. Printing Intermediate Code 847
  • 881.
    Ring Documentation, Release1.10 =================================================== Byte Code - Before Execution by the VM =================================================== PC OPCode Data 1 ReturnNull 2 Func main 3 NewLine 2 4 FuncExE 5 PushC Hello World 6 LoadA nl 0 7 PushV 8 SUM 0 9 Print 10 NewLine 3 11 ExitMark 29 28 12 LoadAFirst x 13 PushN 1.000000 14 BeforeEqual 0 15 Assignment 16 PushN 1.000000 17 StepNumber 18 JumpVarLENum x 10.000000 29 19 NewLine 4 20 FuncExE 21 LoadA x 0 22 PushV 23 LoadA nl 0 24 PushV 25 SUM 0 26 Print 27 NewLine 5 28 IncJump x 18 29 POPExitMark 30 POPStep 31 NewLine 6 32 LoadFunc test 33 Call 0 34 NoOperation 35 NewLine 8 36 PushV 37 FreeStack 38 ReturnNull 39 Func test 40 NewLine 9 41 FuncExE 42 PushC welcome 43 LoadA nl 0 44 PushV 45 SUM 0 46 Print 47 NewLine 10 48 LoadA o1 0 49 AssignmentPointer 50 New point 51 SetScope 52 PushV 74.3. Printing Intermediate Code 848
  • 882.
    Ring Documentation, Release1.10 53 BraceStart 54 LoadA x 0 58 55 AssignmentPointer 56 PushN 10.000000 57 BeforeEqual 0 58 Assignment 0 0 59 FreeStack 60 LoadA y 0 64 61 AssignmentPointer 62 PushN 20.000000 63 BeforeEqual 0 64 Assignment 0 0 65 FreeStack 66 LoadA z 0 70 67 AssignmentPointer 68 PushN 30.000000 69 BeforeEqual 0 70 Assignment 0 0 71 FreeStack 72 LoadFunc ismethod 73 LoadA self 0 74 PushV 75 PushC braceend 76 Call 77 NoOperation 78 PushV 79 JumpZ 85 80 LoadFunc braceend 81 Call 82 NoOperation 83 PushV 84 FreeStack 85 BraceEnd 86 FreeStack 87 NewLine 11 88 FuncExE 89 LoadA o1 0 90 PushV 91 Print 92 NewLine 13 93 ReturnNull 94 Class point 006E8BC0 95 NewLabel 96 LoadA x 0 97 PushV 98 FreeStack 99 LoadA y 0 100 PushV 101 FreeStack 102 LoadA z 0 103 PushV 104 FreeStack 105 ReturnNull =================================================== 74.3. Printing Intermediate Code 849
  • 883.
    Ring Documentation, Release1.10 74.4 Printing Final Intermediate Code Command: ring test.ring -icfinal Output: Hello World 1 2 3 4 5 6 7 8 9 10 welcome x: 10.000000 y: 20.000000 z: 30.000000 =================================================== Byte Code - After Execution by the VM =================================================== PC OPCode Data 1 ReturnNull 2 Func main 3 NewLine 2 4 FuncExE 5 PushC Hello World 6 PushP 007D3670 0 7 PushV 8 SUM 0 9 Print 10 NewLine 3 11 ExitMark 29 28 12 LoadAFirst x 13 PushN 1.000000 14 BeforeEqual 0 15 Assignment 16 PushN 1.000000 17 StepNumber 18 JumpVarLPLENum x 10.000000 29 19 NewLine 4 20 FuncExE 21 PushPLocal x 0 22 PushV 23 PushP 007D3670 0 24 PushV 25 SUM 0 26 Print 27 NewLine 5 74.4. Printing Final Intermediate Code 850
  • 884.
    Ring Documentation, Release1.10 28 IncLPJump x 18 29 POPExitMark 30 POPStep 31 NewLine 6 32 LoadFuncP test 33 Call 0 34 NoOperation 35 NewLine 8 36 PushV 37 FreeStack 38 ReturnNull 39 Func test 40 NewLine 9 41 FuncExE 42 PushC welcome 43 PushP 007D3670 0 44 PushV 45 SUM 0 46 Print 47 NewLine 10 48 PushPLocal o1 0 49 AssignmentPointer 50 New point 51 SetScope 52 PushV 53 BraceStart 54 LoadA x 0 58 55 AssignmentPointer 56 PushN 10.000000 57 BeforeEqual 0 58 SetProperty 0 106 59 FreeStack 60 LoadA y 0 64 61 AssignmentPointer 62 PushN 20.000000 63 BeforeEqual 0 64 SetProperty 0 141 65 FreeStack 66 LoadA z 0 70 67 AssignmentPointer 68 PushN 30.000000 69 BeforeEqual 0 70 SetProperty 0 176 71 FreeStack 72 LoadFunc ismethod 73 LoadA self 0 74 PushV 75 PushC braceend 76 Call 77 NoOperation 78 PushV 79 JumpZ 85 80 LoadFunc braceend 81 Call 82 NoOperation 83 PushV 84 FreeStack 85 BraceEnd 74.4. Printing Final Intermediate Code 851
  • 885.
    Ring Documentation, Release1.10 86 FreeStack 87 NewLine 11 88 FuncExE 89 PushPLocal o1 0 90 PushV 91 Print 92 NewLine 13 93 ReturnNull 94 Class point 007D8470 95 NewLabel 96 LoadA x 0 97 PushV 98 FreeStack 99 LoadA y 0 100 PushV 101 FreeStack 102 LoadA z 0 103 PushV 104 FreeStack 105 ReturnNull 106 LoadFunc ismethod 107 LoadA ring_gettemp_var 0 108 PushV 109 PushC setx 110 Call 0 111 NoOperation 112 PushV 113 JumpZ 132 114 NewLine 2 115 LoadA ring_gettemp_var 0 116 LoadMethod setx 117 LoadA ring_settemp_var 0 118 PushV 119 Call 0 1 120 AfterCallMethod 121 PushV 122 FreeStack 123 NewLine 3 124 LoadA ring_tempflag_var 0 128 125 AssignmentPointer 126 PushN 0.000000 127 BeforeEqual 0 128 Assignment 0 0 129 FreeStack 130 NewLine 4 131 Jump 140 132 NewLine 5 133 PushP 007D37D8 0 137 134 AssignmentPointer 135 PushN 1.000000 136 BeforeEqual 0 137 Assignment 0 0 138 FreeStack 139 NewLine 6 140 Return 141 LoadFunc ismethod 142 LoadA ring_gettemp_var 0 143 PushV 74.4. Printing Final Intermediate Code 852
  • 886.
    Ring Documentation, Release1.10 144 PushC sety 145 Call 0 146 NoOperation 147 PushV 148 JumpZ 167 149 NewLine 2 150 LoadA ring_gettemp_var 0 151 LoadMethod sety 152 LoadA ring_settemp_var 0 153 PushV 154 Call 0 1 155 AfterCallMethod 156 PushV 157 FreeStack 158 NewLine 3 159 LoadA ring_tempflag_var 0 163 160 AssignmentPointer 161 PushN 0.000000 162 BeforeEqual 0 163 Assignment 0 0 164 FreeStack 165 NewLine 4 166 Jump 175 167 NewLine 5 168 PushP 007D37D8 0 172 169 AssignmentPointer 170 PushN 1.000000 171 BeforeEqual 0 172 Assignment 0 0 173 FreeStack 174 NewLine 6 175 Return 176 LoadFunc ismethod 177 LoadA ring_gettemp_var 0 178 PushV 179 PushC setz 180 Call 0 181 NoOperation 182 PushV 183 JumpZ 202 184 NewLine 2 185 LoadA ring_gettemp_var 0 186 LoadMethod setz 187 LoadA ring_settemp_var 0 188 PushV 189 Call 0 1 190 AfterCallMethod 191 PushV 192 FreeStack 193 NewLine 3 194 LoadA ring_tempflag_var 0 198 195 AssignmentPointer 196 PushN 0.000000 197 BeforeEqual 0 198 Assignment 0 0 199 FreeStack 200 NewLine 4 201 Jump 210 74.4. Printing Final Intermediate Code 853
  • 887.
    Ring Documentation, Release1.10 202 NewLine 5 203 PushP 007D37D8 0 207 204 AssignmentPointer 205 PushN 1.000000 206 BeforeEqual 0 207 Assignment 0 0 208 FreeStack 209 NewLine 6 210 Return =================================================== 74.5 CGI Support Command: ring test.ring -cgi 74.6 No Run Command: ring test.ring -norun 74.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! 74.8 Performance Command: 74.5. CGI Support 854
  • 888.
    Ring Documentation, Release1.10 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 9 10 welcome x: 10.000000 y: 20.000000 z: 30.000000 =================================================== Date : 2015/09/15 Time : 15:56:17 Clock : 0 =================================================== 74.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 74.9. Generate Object File 855
  • 889.
    CHAPTER SEVENTYFIVE PERFORMANCE TIPS In thischapter we will learn more about the Ring performance. 75.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 856
  • 890.
    Ring Documentation, Release1.10 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: 75.1. Introduction 857
  • 891.
    Ring Documentation, Release1.10 75.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: 75.2. Creating Lists 858
  • 892.
    Ring Documentation, Release1.10 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 75.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 75.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" ? "Using len() before the For loop" t1 = clock() nMax = len(aList) 75.3. Arithmetic Operations 859
  • 893.
    Ring Documentation, Release1.10 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. 75.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: 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. 75.5. Calling Functions and Methods 860
  • 894.
    Ring Documentation, Release1.10 Note: Using the dot operator to call methods is faster than using braces. 75.5. Calling Functions and Methods 861
  • 895.
    CHAPTER SEVENTYSIX DISTRIBUTING RING APPLICATIONS Inthis 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! 76.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. 76.2 Protecting the Source Code Step 1: Execute the next command ring myapp.ring -go 862
  • 896.
    Ring Documentation, Release1.10 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. 76.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) 76.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 76.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. 76.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. 76.3. The files ring.ring and ring.ringo 863
  • 897.
    CHAPTER SEVENTYSEVEN 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 and Mobile devices Note: We can use the Distribute Menu in the Ring Notepad application (More Easy) 77.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 ge generated by the Visual C/C++ Linker) filename (Executable File - On Linux & MacOS X platforms) 77.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. So it’s better and easy to have a C compiler on your machine to be used by Ring2EXE. 864
  • 898.
    Ring Documentation, Release1.10 77.3 Example We have test.ring contains the next code see "Hello, World!" + nl To build th executable file for Windows, Linux or macOS ring2exe test.ring To run the program (Windows) test To run the program (Linux and macOS) ./test 77.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 -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 -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 77.3. Example 865
  • 899.
    Ring Documentation, Release1.10 77.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 77.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 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 77.5. Building standalone console application 866
  • 900.
    Ring Documentation, Release1.10 77.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 77.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 77.7. Distributing RingQt Applications 867
  • 901.
    Ring Documentation, Release1.10 77.9 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) 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! 77.10 Building the Weight History Application for Mobile using RingQt Another example to distribute your application for Mobile Devices using Ring2EXE and Qt 77.9. Building the Cards Game for Mobile using RingQt 868
  • 902.
    Ring Documentation, Release1.10 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 <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. 77.11 Building the Form Designer for Mobile using RingQt To build the Form Designer application (ring/applications/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 77.11. Building the Form Designer for Mobile using RingQt 869
  • 903.
    Ring Documentation, Release1.10 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> <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/applications/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")) 77.11. Building the Form Designer for Mobile using RingQt 870
  • 904.
    Ring Documentation, Release1.10 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") } ] tool1 = win.addtoolbar("files") { for x in aBtns { addwidget(x) addseparator() } } From this example, We know that we can use sub folders for images. 77.12 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! 77.13 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 77.12. Creating the Qt resource file using Folder2qrc 871
  • 905.
    Ring Documentation, Release1.10 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/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/ring2exe/libs 77.13. Important Information about Ring2EXE 872
  • 906.
    CHAPTER SEVENTYEIGHT 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. 78.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 78.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 registred packages. ringpm search [keywords...] Example: ringpm search notepad Output: Package : ringnotepad (Ring Notepad) Package : notepadppeditorextension (Notepad++ Editor Extension package) 873
  • 907.
    Ring Documentation, Release1.10 To print all packages in the RingPM Registry, use the search command without keywords. Example: ringpm search 78.3 Updating the RingPM Registry The RingPM Registry is a local copy of all registred 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) 78.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 ringpm run firstpackage 78.3. Updating the RingPM Registry 874
  • 908.
    Ring Documentation, Release1.10 To install a package in the current folder Example (5) : ringpm install 78.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 78.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 To run a package in the current folder Example(4): ringpm run 78.5. Printing List of Installed Packages 875
  • 909.
    Ring Documentation, Release1.10 78.7 Update Package We can update a package using the Update command ringpm update <packagename> Example: ringpm update ringnotepad 78.8 Remove Package We can remove a package using the Remove command ringpm remove <packagename> Example: ringpm remove ringnotepad 78.9 Deleting All Packages We can delete all packages using the Format command Example: ringpm format 78.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 • 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" 78.7. Update Package 876
  • 910.
    Ring Documentation, Release1.10 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 = [ ], :macosfiles = [ ], :windowsringfolderfiles = [ ], :linuxringfolderfiles = [ 78.10. Creating New Package 877
  • 911.
    Ring Documentation, Release1.10 ], :ubunturingfolderfiles = [ ], :fedoraringfolderfiles = [ ], :macosringfolderfiles = [ ], :run = "ring main.ring", :windowsrun = "", :linuxrun = "", :macosrun = "", :ubunturun = "", :fedorarun = "", :setup = "", :windowssetup = "", :linuxsetup = "", :macossetup = "", :ubuntusetup = "", :fedorasetup = "", :remove = "", :windowsremove = "", :linuxremove = "", :macosremove = "", :ubunturemove = "", :fedoraremove = "" ] 78.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 Desciption 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) 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 Continued on next page 78.11. The Package Description File 878
  • 912.
    Ring Documentation, Release1.10 Table 78.1 – continued from previous page Attribute Description 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 78.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 aPackageInfo = [ :name = "The RingNotepad Package", :description = "Our RingNotepad package using the Ring programming language", :folder = "ringnotepad", :developer = "Mahmoud Fayed", :email = "msfclipper@yahoo.com", :license = "MIT License", :version = "1.0.0", :ringversion = "1.10", :versions = [ [ 78.12. Create Package in the Current Folder 879
  • 913.
    Ring Documentation, Release1.10 :version = "1.0.0", :branch = "master" ] ], :libs = [ [ :name = "stdlib", :version = "1.0", :providerusername = "" ], [ :name = "ringqt", :version = "1.0", :providerusername = "" ], [ :name = "findinfiles", :version = "1.0", :providerusername = "" ], [ :name = "formdesigner", :version = "1.0", :providerusername = "" ], [ :name = "libdepwin_apache", :version = "1.0", :providerusername = "" ] ], :files = [ "main.ring", "README.md" ], :ringfolderfiles = [ "applications/rnote/batch/killwebserver.bat", "applications/rnote/batch/run.bat", "applications/rnote/batch/run2.bat", "applications/rnote/image/back.jpg", "applications/rnote/image/back2.jpg", "applications/rnote/image/close.png", "applications/rnote/image/colors.png", "applications/rnote/image/copy.png", "applications/rnote/image/cut.png", "applications/rnote/image/debug.png", "applications/rnote/image/font.png", "applications/rnote/image/formdesigner.png", "applications/rnote/image/new.png", "applications/rnote/image/notepad.png", "applications/rnote/image/open.png", "applications/rnote/image/paste.png", "applications/rnote/image/print.png", "applications/rnote/image/project.png", "applications/rnote/image/richtext.png", "applications/rnote/image/run.png", "applications/rnote/image/rungui.png", "applications/rnote/image/save.png", 78.12. Create Package in the Current Folder 880
  • 914.
    Ring Documentation, Release1.10 "applications/rnote/image/saveas.png", "applications/rnote/image/search.png", "applications/rnote/image/source.png", "applications/rnote/image/undo.png", "applications/rnote/image/web.png", "applications/rnote/README.md", "applications/rnote/rnote.ring", "applications/rnote/rnoteactivefile.ring", "applications/rnote/rnoteactivefolder.ring", "applications/rnote/rnoteautocomplete.ring", "applications/rnote/rnotebase.ring", "applications/rnote/rnotecontroller.ring", "applications/rnote/rnotedistribute.ring", "applications/rnote/rnoteeditmenu.ring", "applications/rnote/rnoteeditorevents.ring", "applications/rnote/rnotefilemenu.ring", "applications/rnote/rnotefiles.ring", "applications/rnote/rnotefilestabs.ring", "applications/rnote/rnotefind.ring", "applications/rnote/rnotefindinfiles.ring", "applications/rnote/rnoteformdesigner.ring", "applications/rnote/rnotegoto.ring", "applications/rnote/rnotehelp.ring", "applications/rnote/rnotelists.ring", "applications/rnote/rnotemainfiletoolbar.ring", "applications/rnote/rnotemainwindow.ring", "applications/rnote/rnotemode.ring", "applications/rnote/rnoteoutputwindow.ring", "applications/rnote/rnoteprogrammenu.ring", "applications/rnote/rnoterun.ring", "applications/rnote/rnotesettings.ring", "applications/rnote/rnotestyle.ring", "applications/rnote/rnotetabwidth.ring", "applications/rnote/rnotetools.ring", "applications/rnote/rnotetreeviewevents.ring", "applications/rnote/rnoteviewmenu.ring", "applications/rnote/rnotewebbrowser.ring" ], :run = "ring main.ring" ] 78.13 The RingPM Registry File The RingPM Registry is a local copy of all registred 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 78.13. The RingPM Registry File 881
  • 915.
    Ring Documentation, Release1.10 • 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/ringpm/registry/registry.ring 78.13. The RingPM Registry File 882
  • 916.
    CHAPTER SEVENTYNINE LOW LEVEL FUNCTIONS Inthis chapter we will learn about the low level functions provided by Ring • callgc() • varptr() • space() • nullpointer() • object2pointer() • pointer2object() • ispointer() • ptrcmp() • ringvm_cfunctionslist() • ringvm_functionslist() • ringvm_classeslist() • ringvm_packageslist() • ringvm_memorylist() • ringvm_calllist() • ringvm_fileslist() • ringvm_settrace() • ringvm_tracedata() • ringvm_traceevent() • ringvm_tracefunc() • ringvm_scopescount() • ringvm_evalinscope() • ringvm_passerror() • ringvm_hideerrorMsg() • ringvm_callfunc() • ringvm_see() • ringvm_give() 883
  • 917.
    Ring Documentation, Release1.10 • ringvm_info() 79.1 callgc() function Use this function to force calling the garbage collector during function execution when you use a loop that create temp. variables that you don’t free using the assignment operation. It’s very rare to need this function but it’s useful when you create something like event-loop for your game engine and start creating lists on the fly when you call functions. Example While True # process events # call functions using temp. lists like myfunc(["temp list"]) # call the garbage collector callgc() End Tip: In Ring the garbage collector works automatically in the end of function execution or when you use the assign- ment statement. 79.2 varptr() function Use the varptr() function when you need to pass a pointer to a C/C++ function. Syntax: varptr(cVariableName,cPointerType) —> Low Level Object (C Pointer) example: r = 10 z = 20 see r + nl see varptr("r","int") see varptr("z","int") Output: 10 00E3C740 int 2 00E3BEC0 int 2 Note: the low level object is a list contains three items (The Pointer, The Type, The Status) 79.1. callgc() function 884
  • 918.
    Ring Documentation, Release1.10 79.3 space() function Use the space function to allocate a specific number of bytes in Memory. Syntax: Space(nBytesCount) ---> String Example: mystring = space(200) See "String Size : " + len(mystring) + nl See "String : " + mystring + nl See "String Pointer : " See varptr("mystring","char *") Output: String Size : 200 String : String Pointer : 00FF8FE8 char * 2 Note: You may need the space() and VarPtr() functions to pass buffers to C functions. 79.4 nullpointer() function You may need to pass the NULL pointer to a C function that may expect a pointer as parameter and accept NULL pointers for optional parameters. Example: The next example uses the SDL_BlitSurface() function from the LibSDL Library through RingSDL The function accept SDL_Rect pointers in the second and the last parameter. Also the function accept NULL pointers, so we can pass them using the NULLPointer() Function. SDL_BlitSurface(text, nullpointer(), surface, nullpointer()) Note: The previous code doesn’t work alone, you need to learn how to use RingSDL first. Tip: We can pass NULL as parameter instead of using NULLPointer() 79.5 object2pointer() function Use this function to get a C pointer for Ring lists and objects Syntax: object2pointer(List|Object) --> Low Level Object ( C Pointer ) 79.3. space() function 885
  • 919.
    Ring Documentation, Release1.10 79.6 pointer2object() function Use this function to get the Ring list and/or object from the low level object (C Pointer) Syntax: pointer2object(Low Level Object) ---> List|Object Example: # Create the list mylist = 1:5 # Create pointer to the list x = object2pointer(mylist) see x see nl # Add items to the list mylist + "welcome" # print the list items y = pointer2object(x) see y Output: 0069A5D8 OBJECTPOINTER 0 1 2 3 4 5 welcome Note: In Ring the assignment operator copy lists and objects by value, to copy by reference Just use the ob- ject2pointer() and pointer2object() functions. Tip: The object2pointer() and pointer2object() are used in the stdlib - Tree Class implementation to create a reference for the parent node (object) in the child node (another object). 79.7 ispointer() function Check if the parameter is a pointer (C Object) or not. Syntax: IsPointer(vPara) ---> True|False Example : 79.6. pointer2object() function 886
  • 920.
    Ring Documentation, Release1.10 fp = fopen(filename(),"r") ? type(fp) ? ispointer(fp) Output : file 1 79.8 ptrcmp() function We can compare between two pointers (C Objects) using the ptrcmp() function. Syntax: ptrcmp(oObject1,oObject2) ---> value = 1 if oObject1 = oObject2 value = 0 if oObject1 != oObject2 Example: fp = fopen("ptrcmp.ring","r") fp2 = fp fp3 = fopen("ptrcmp.ring","r") see ptrcmp(fp,fp2) + nl see ptrcmp(fp,fp3) + nl fclose(fp) fclose(fp3) Output: 1 0 79.9 ringvm_cfunctionslist() function The Function return a list of functions written in C. Syntax: RingVM_CFunctionsList() ---> List Example: See RingVM_CFunctionsList() 79.10 ringvm_functionslist() function The Function return a list of functions written in Ring. Each List Member is a list contains the next items 79.8. ptrcmp() function 887
  • 921.
    Ring Documentation, Release1.10 • Function Name • Program Counter (PC) - Function Position in Byte Code. • Source Code File Name • Private Flag (For Private Methods in Classes) Syntax: RingVM_FunctionsList() ---> List Example: test() func test see ringvm_functionslist() Output: test 8 B:/ring/tests/scripts/functionslist.ring 0 79.11 ringvm_classeslist() function The Function return a list of Classes. Each List Member is a list contains the next items • Class Name • Program Counter (PC) - Class Position in Byte Code. • Parent Class Name • Methods List • Flag (Is parent class information collected) • Pointer to the package (or NULL if no package is used) Syntax: RingVM_ClassesList() ---> List Example: see ringvm_classeslist() class class1 func f1 class class2 from class1 class class3 from class1 Output: class1 9 79.11. ringvm_classeslist() function 888
  • 922.
    Ring Documentation, Release1.10 f1 13 B:/ring/tests/scripts/classeslist.ring 0 0 00000000 class2 16 class1 0 00000000 class3 20 class1 0 00000000 79.12 ringvm_packageslist() function The Function return a list of Packages. Each List Member is a list contains the next items • Package Name • Classes List Syntax: RingVM_PackagesList() ---> List Example: see ringvm_packageslist() package package1 class class1 package package2 class class1 package package3 class class1 Output: package1 class1 11 0 00FEF838 package2 class1 17 0 00FEF978 79.12. ringvm_packageslist() function 889
  • 923.
    Ring Documentation, Release1.10 package3 class1 23 0 00FEFF68 79.13 ringvm_memorylist() function The Function return a list of Memory Scopes and Variables. Each List Member is a list contains variables in a different scope. Each Item in the scope list is a list contains the next items • Variable Name • Variable Type • Variable Value • Pointer Type (List/Item) if the value is a list • Private Flag (if the variable is an attribute in a Class) Syntax: RingVM_MemoryList() ---> List Example: x = 10 test() func test y = 20 see ringvm_memorylist() Output: true 2 1 0 0 false 2 0 0 0 nl 1 0 0 null 1 0 0 79.13. ringvm_memorylist() function 890
  • 924.
    Ring Documentation, Release1.10 ring_gettemp_var 4 00000000 0 0 ccatcherror 1 NULL 0 0 ring_settemp_var 4 00000000 0 0 ring_tempflag_var 2 0 0 0 stdin 3 50512DB8 file 0 0 0 stdout 3 50512DD8 file 0 0 0 stderr 3 50512DF8 file 0 0 0 this 4 00000000 0 0 sysargv 3 B:ringbin/ring B:/ring/tests/scripts/memorylist.ring 0 0 x 2 10 0 0 y 79.13. ringvm_memorylist() function 891
  • 925.
    Ring Documentation, Release1.10 2 20 0 0 79.14 ringvm_calllist() function The Function return a list of the functions call list. Each List Member is a list contains the next items • Function Type • Function Name • Program Counter (PC) • Stack Pointer (SP) • Temp. Memory List • Method or Function Flag • Caller PC • FuncExec Flag • ListStart Flag • Nested Lists Pointer • State List Syntax: RingVM_CallList() ---> List Example: hello() func hello test() func test mylist = ringvm_calllist() for t in mylist see t[2] + nl next Output: function hello() in file B:/ring/tests/scripts/calllist.ring called from line 1 function test() in file B:/ring/tests/scripts/calllist.ring called from line 3 ringvm_calllist 79.15 ringvm_fileslist() function Function return a list of the Ring Files. 79.14. ringvm_calllist() function 892
  • 926.
    Ring Documentation, Release1.10 Syntax: RingVM_FilesList() ---> List Example: load "stdlib.ring" see ringvm_fileslist() Output: B:/ring/tests/scripts/fileslist.ring B:ringbinstdlib.ring eval stdlib.ring stdlib.rh stdclasses.ring stdfunctions.ring stdbase.ring stdstring.ring stdlist.ring stdstack.ring stdqueue.ring stdmath.ring stddatetime.ring stdfile.ring stdsystem.ring stddebug.ring stddatatype.ring stdconversion.ring stdodbc.ring stdmysql.ring stdsecurity.ring stdinternet.ring stdhashtable.ring stdtree.ring 79.16 ringvm_settrace() The function ringvm_settrace() determine the Trace function name The trace function is a Ring function that will be called for each event Syntax: RingVM_SetTrace(cCode) 79.17 ringvm_tracedata() Inside the function that we will use for tracing events We can use the ringvm_tracedata() function to get the event data. The event data is a list contains the next items • The Source Code Line Number 79.16. ringvm_settrace() 893
  • 927.
    Ring Documentation, Release1.10 • The Source File Name • The Function/Method Name • Method or Function (Bool : True=Method, False=Function/File) Syntax: RingVM_TraceData() ---> aDataList 79.18 ringvm_traceevent() Inside the function that we will use for tracing events We can use ringvm_traceevent() to know the event type • New Line • Before Function • After Function • Runtime Error • Before C Function • After C Function Syntax: RingVM_TraceEvent() ---> nTraceEvent 79.19 ringvm_tracefunc() The function return the name of the function that we are using for tracing events. Syntax: RingVM_TraceEvent() ---> cCode 79.20 ringvm_scopescount() We can use the RingVM_ScopesCount() function to know the number of scopes used in the application. In the start of the program, We have the (global scope only) When we call a function, A new scope is created. When the function execution is done, the function scope is deleted. Syntax: RingVM_ScopesCount() ---> nScopes 79.18. ringvm_traceevent() 894
  • 928.
    Ring Documentation, Release1.10 79.21 ringvm_evalinscope() The function ringvm_evalinscope() is similar to the eval() function Unlike eval() which execute the code in the current scope Using RingVM_EvalInScope() we can execute the scope in a specific scope. Syntax: RingVM_EvalInScope(nScope,cCode) 79.22 ringvm_passerror() When we have runtime error, After printing the Error message, Ring will end the execution of the program. Using ringvm_passerror() we can avoid that, and continue the execution of our program. Syntax: RingVM_PassError() 79.23 ringvm_hideerrormsg() We can disable/enable displaying the runtime error messages using the RingVM_HideErrorMsg() function. Syntax: RingVM_HideErrorMsg(lStatus) 79.24 ringvm_callfunc() We can call a function from a string without using eval() using the ringvm_callfunc() Syntax: RingVM_CallFunc(cFuncName) 79.25 Example - Using the Trace Functions The next example use the Trace Functions to trace the program Events! In practical, We will use the Trace Library instead of these low level functions! load "tracelib.ring" ringvm_settrace("mytrace()") see "Hello, world!" + nl see "Welcome" + nl see "How are you?" +nl mytest() 79.21. ringvm_evalinscope() 895
  • 929.
    Ring Documentation, Release1.10 new myclass { mymethod() } func mytest see "Message from mytest" + nl func mytrace see "====== The Trace function is Active ======" + nl + "Trace Function Name : " + ringvm_TraceFunc() + nl + "Trace Event : " switch ringvm_TraceEvent() on TRACEEVENT_NEWLINE see "New Line" on TRACEEVENT_NEWFUNC see "New Function" on TRACEEVENT_RETURN see "Return" on TRACEEVENT_ERROR see "Error" on TRACEEVENT_BEFORECFUNC see "Before C Function" on TRACEEVENT_AFTERCFUNC see "After C Function" off see nl + "Line Number : " + ringvm_tracedata()[TRACEDATA_LINENUMBER] + nl + "File Name : " + ringvm_tracedata()[TRACEDATA_FILENAME] + nl + "Function Name : " + ringvm_tracedata()[TRACEDATA_FUNCNAME] + nl + "Method or Function : " if ringvm_tracedata()[TRACEDATA_METHODORFUNC] = TRACEDATA_METHODORFUNC_METHOD see "Method" else if ringvm_tracedata()[TRACEDATA_FUNCNAME] = NULL see "Command" else see "Function" ok ok see nl + Copy("=",42) + nl class myclass func mymethod see "Message from mymethod" + nl Output: ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : After C Function Line Number : 3 File Name : test1.ring Function Name : ringvm_settrace Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 5 File Name : test1.ring Function Name : Method or Function : Command ========================================== Hello, world! ====== The Trace function is Active ====== 79.25. Example - Using the Trace Functions 896
  • 930.
    Ring Documentation, Release1.10 Trace Function Name : mytrace() Trace Event : New Line Line Number : 6 File Name : test1.ring Function Name : Method or Function : Command ========================================== Welcome ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 7 File Name : test1.ring Function Name : Method or Function : Command ========================================== How are you? ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 8 File Name : test1.ring Function Name : Method or Function : Command ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Function Line Number : 8 File Name : test1.ring Function Name : mytest Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 12 File Name : test1.ring Function Name : mytest Method or Function : Function ========================================== Message from mytest ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 14 File Name : test1.ring Function Name : mytest Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : Return Line Number : 8 File Name : test1.ring Function Name : Method or Function : Command ========================================== 79.25. Example - Using the Trace Functions 897
  • 931.
    Ring Documentation, Release1.10 ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 9 File Name : test1.ring Function Name : Method or Function : Command ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 43 File Name : test1.ring Function Name : Method or Function : Command ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : Before C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : After C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Function Line Number : 9 File Name : test1.ring Function Name : mymethod Method or Function : Method ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 44 File Name : test1.ring Function Name : mymethod Method or Function : Method ========================================== Message from mymethod ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : Return Line Number : 9 File Name : test1.ring Function Name : Method or Function : Command ========================================== ====== The Trace function is Active ====== 79.25. Example - Using the Trace Functions 898
  • 932.
    Ring Documentation, Release1.10 Trace Function Name : mytrace() Trace Event : Before C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : After C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : Before C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : After C Function Line Number : 9 File Name : test1.ring Function Name : ismethod Method or Function : Function ========================================== ====== The Trace function is Active ====== Trace Function Name : mytrace() Trace Event : New Line Line Number : 11 File Name : test1.ring Function Name : Method or Function : Command ========================================== 79.26 Example - The Trace Library The next example uses the Trace functions provided by the Ring language to create the Trace library. Using the Trace library we have nice Tracing tools and Interaction debugger too. # Trace Events TRACEEVENT_NEWLINE = 1 TRACEEVENT_NEWFUNC = 2 TRACEEVENT_RETURN = 3 TRACEEVENT_ERROR = 4 TRACEEVENT_BEFORECFUNC = 5 TRACEEVENT_AFTERCFUNC = 6 # Trace Data TRACEDATA_LINENUMBER = 1 79.26. Example - The Trace Library 899
  • 933.
    Ring Documentation, Release1.10 TRACEDATA_FILENAME = 2 TRACEDATA_FUNCNAME = 3 TRACEDATA_METHODORFUNC = 4 # Method of Function TRACEDATA_METHODORFUNC_METHOD = TRUE TRACEDATA_METHODORFUNC_NOTMETHOD = FALSE TRACE_BREAKPOINTS = TRUE TRACE_TEMPLIST = [] func Trace cType switch trim(lower(cType)) on :AllEvents ringvm_settrace("TraceLib_AllEvents()") on :Functions ringvm_settrace("TraceLib_Functions()") on :PassError ringvm_settrace("TraceLib_PassError()") on :Debugger ringvm_settrace("TraceLib_Debugger()") on :LineByLine ringvm_settrace("TraceLib_LineByLine()") off func TraceLib_AllEvents if right(ringvm_tracedata()[TRACEDATA_FILENAME],13) = "tracelib.ring" return ok see "====== The Trace function is Active ======" + nl + "Trace Function Name : " + ringvm_TraceFunc() + nl + "Trace Event : " switch ringvm_TraceEvent() on TRACEEVENT_NEWLINE see "New Line" on TRACEEVENT_NEWFUNC see "New Function" on TRACEEVENT_RETURN see "Return" on TRACEEVENT_ERROR see "Error" on TRACEEVENT_BEFORECFUNC see "Before C Function" on TRACEEVENT_AFTERCFUNC see "After C Function" off see nl + "Line Number : " + ringvm_tracedata()[TRACEDATA_LINENUMBER] + nl + "File Name : " + ringvm_tracedata()[TRACEDATA_FILENAME] + nl + "Function Name : " + ringvm_tracedata()[TRACEDATA_FUNCNAME] + nl + "Method or Function : " if ringvm_tracedata()[TRACEDATA_METHODORFUNC] = TRACEDATA_METHODORFUNC_METHOD see "Method" else if ringvm_tracedata()[TRACEDATA_FUNCNAME] = NULL see "Command" else see "Function" ok ok see nl + Copy("=",42) + nl 79.26. Example - The Trace Library 900
  • 934.
    Ring Documentation, Release1.10 func TraceLib_Functions if right(ringvm_tracedata()[TRACEDATA_FILENAME],13) = "tracelib.ring" return ok switch ringvm_TraceEvent() on TRACEEVENT_NEWFUNC see "Open Func : " + ringvm_TraceData()[TRACEDATA_FUNCNAME] + nl on TRACEEVENT_RETURN see "Return to Func : " + ringvm_TraceData()[TRACEDATA_FUNCNAME] + nl off func TraceLib_PassError if right(ringvm_tracedata()[TRACEDATA_FILENAME],13) = "tracelib.ring" return ok switch ringvm_TraceEvent() on TRACEEVENT_ERROR see nl see "TraceLib : After Error !" + nl ringvm_passerror() off func TraceLib_Debugger if right(ringvm_tracedata()[TRACEDATA_FILENAME],13) = "tracelib.ring" return ok switch ringvm_TraceEvent() on TRACEEVENT_ERROR _BreakPoint() off func TraceLib_LineByLine if right(ringvm_tracedata()[TRACEDATA_FILENAME],13) = "tracelib.ring" or ringvm_TraceEvent() != TRACEEVENT_NEWLINE return ok aList = ringvm_tracedata() see "Before Line : " + aList[TRACEDATA_LINENUMBER] + nl _BreakPoint() func BreakPoint if not TRACE_BREAKPOINTS return ok _BreakPoint() func _BreakPoint see nl+nl+Copy("=",60) + nl + Copy(" ",20)+"Interactive Debugger" + nl + Copy("=",60) + nl + "Command (Exit) : End Program" + nl + "Command (Cont) : Continue Execution" + nl + "Command (Locals) : Print local variables names" + nl + "Command (LocalsData) : Print local variables data" + nl + "Command (Globals) : Print global variables names" + nl + "We can execute Ring code" + nl + 79.26. Example - The Trace Library 901
  • 935.
    Ring Documentation, Release1.10 Copy("=",60) + nl while true see nl + "code:> " give cCode cmd = trim(lower(cCode)) if cmd = "exit" or cmd = "bye" shutdown() ok nScope = ringvm_scopescount()-2 switch cmd on "locals" ringvm_EvalInScope(nScope,"see locals() callgc()") loop on "localsdata" PrintLocalsData(nScope) loop on "globals" ringvm_EvalInScope(nScope,"see globals() callgc()") loop on "cont" ringvm_passerror() exit off Try ringvm_EvalInScope(nScope,cCode) catch see cCatchError done end func NoBreakPoints TRACE_BREAKPOINTS = FALSE func PrintLocalsData nScope if nScope = 1 # Global ringvm_Evalinscope(nScope,'TRACE_TEMPLIST = globals()') else ringvm_Evalinscope(nScope,'TRACE_TEMPLIST = locals() callgc()') ok see nl aTempList = TRACE_TEMPLIST TRACE_TEMPLIST = [] nSpaces = 5 for TRACE_ITEM in aTempList if len(TRACE_ITEM) + 5 > nSpaces nSpaces = len(TRACE_ITEM) + 5 ok next for TRACE_ITEM in aTempList see "Variable : " + TRACE_ITEM cVarName = TRACE_ITEM see copy(" ",nSpaces-len(cVarName)) + " Type : " ringvm_Evalinscope(nScope,"see type(" + TRACE_ITEM +")") ringvm_Evalinscope(nScope,"see Copy(' ',fabs(15-len(type(" + TRACE_ITEM +"))))") see " Value : " ringvm_Evalinscope(nScope,"see " + TRACE_ITEM) 79.26. Example - The Trace Library 902
  • 936.
    Ring Documentation, Release1.10 see nl next 79.27 ringvm_see() function Using the ringvm_see() function we can redefine the behavior of the See command Also we can use ring_see() to have the original behavior Example: see "Hello world" + nl see 123 + nl see ["one","two","three"] see new point {x=10 y=20 z=30} func ringvm_see t ring_see("We want to print: ") ring_See(t) class point x y z Output: We want to print: Hello world We want to print: 123 We want to print: one two three We want to print: x: 10.000000 y: 20.000000 z: 30.000000 79.28 ringvm_give() function Using the ringvm_give() function we can redefine the behavior of the Give command Example: see "Name: " give name see "Hello " + name func ringvm_give see "Mahmoud" + nl return "Mahmoud" Output: Name: Mahmoud Hello Mahmoud 79.29 ringvm_info() function The ringvm_info() is an internal function that return a list of information about the Ring VM structure. 79.27. ringvm_see() function 903
  • 937.
    Ring Documentation, Release1.10 It’s used only by the Ring Team in advanced tests to check the VM status. Syntax: ringvm_info() ---> List of information about the VM structure 79.29. ringvm_info() function 904
  • 938.
    CHAPTER EIGHTY THE TRACE LIBRARYAND THE INTERACTIVE DEBUGGER In this chapter we will learn about the Trace Library and the Interactive Debugger 80.1 Loading the Trace library To start using the Trace library, We must load it first! load "tracelib.ring" 80.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 80.3 Trace control flow between functions The next example demonstrates the Trace library usage to trace the control flow between functions. Trace(:Functions) test1() 905
  • 939.
    Ring Documentation, Release1.10 func test1 see :test1 + nl test2() func test2 see :test2 + nl see test3() + nl func test3 see :test3 + nl return "test 3 output" 80.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!" 80.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 80.6 Execute Program Line by Line The next example demonstrates the Trace library usage to execute the program line by line! Trace(:LineByLine) test1() 80.4. Pass Error 906
  • 940.
    Ring Documentation, Release1.10 func test1 x = 10 see :test1 + nl t = 12 test2() see "After Error!" +nl see "t = " + t + nl 80.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 80.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 80.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 80.7. BreakPoint 907
  • 941.
    Ring Documentation, Release1.10 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 80.9. Using the Interactive Debugger 908
  • 942.
    Ring Documentation, Release1.10 We can run the Interactive Debugger in the Output Window 80.9. Using the Interactive Debugger 909
  • 943.
    CHAPTER EIGHTYONE EMBEDDING RING INRING In this chapter we will learn about embedding Ring in Ring programs and applications. 81.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 10 20 910
  • 944.
    Ring Documentation, Release1.10 81.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') 81.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() } exec() } func test pState = ring_state_init() ring_state_runcode(pstate,"load 'guilib.ring'") ring_state_runcode(pState,"x = NULL") # Pass String 81.2. Serial Execution of Programs 911
  • 945.
    Ring Documentation, Release1.10 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 enviroment ring_state_runcode(pState," new qWidget { pObject = x setwindowtitle('Message from the Sub Ring Environment') } ") ring_state_delete(pState) 81.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 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() 81.4. ring_state_new() and ring_state_mainfile() 912
  • 946.
    Ring Documentation, Release1.10 } 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! 81.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! 81.5. Runtime Errors when Embedding Ring in Ring 913
  • 947.
    CHAPTER EIGHTYTWO EXTENSION USING THEC/C++ LANGUAGES We can extend the Ring Virtual Machine (RingVM) by adding new functions written in the C programming language or C++. The RingVM comes with many functions written in C that we can call like any Ring function. We can extend the language by writing new functions then rebuilding the RingVM again, or we can create shared library (DLL/So) file to extend the RingVM without the need to rebuild it. The Ring language source code comes with two files to add new modules to the RingVM, ring_ext.h and ring_ext.c 82.1 ring_ext.h The file ring_ext.h contains constants that we can change to include/exclude modules during the build process. #ifndef ringext_h #define ringext_h /* Constants */ #define RING_VM_LISTFUNCS 1 #define RING_VM_REFMETA 1 #define RING_VM_MATH 1 #define RING_VM_FILE 1 #define RING_VM_OS 1 #define RING_VM_MYSQL 1 #define RING_VM_ODBC 1 #define RING_VM_OPENSSL 1 #define RING_VM_CURL 1 #define RING_VM_DLL 1 #endif 82.2 ring_ext.c The file ring_ext.c check constants defined in ring_ext.h before calling the start-up function in each module. Each module contains a function that register the module functions in the RingVM. #include "ring.h" void ring_vm_extension ( RingState *pRingState ) { /* Reflection and Meta-programming */ #if RING_VM_REFMETA ring_vm_refmeta_loadfunctions(pRingState); #endif 914
  • 948.
    Ring Documentation, Release1.10 /* List Functions */ #if RING_VM_LISTFUNCS ring_vm_listfuncs_loadfunctions(pRingState); #endif /* Math */ #if RING_VM_MATH ring_vm_math_loadfunctions(pRingState); #endif /* File */ #if RING_VM_FILE ring_vm_file_loadfunctions(pRingState); #endif /* OS */ #if RING_VM_OS ring_vm_os_loadfunctions(pRingState); #endif /* MySQL */ #if RING_VM_MYSQL ring_vm_mysql_loadfunctions(pRingState); #endif /* ODBC */ #if RING_VM_ODBC ring_vm_odbc_loadfunctions(pRingState); #endif /* OPENSSL */ #if RING_VM_OPENSSL ring_vm_openssl_loadfunctions(pRingState); #endif /* CURL */ #if RING_VM_CURL ring_vm_curl_loadfunctions(pRingState); #endif /* DLL */ #if RING_VM_DLL ring_vm_dll_loadfunctions(pRingState); #endif } 82.3 Module Organization Each module starts by include the ring header file (ring.h). This files contains the Ring API that we can use to extend the RingVM. Each module comes with a function to register the module functions in the RingVM The registration is done by using ring_vm_funcregister() function. The ring_vm_funcregister() function takes two parameters, the first is the function name that will be used by Ring programs to call the function. The second parameter is the function pointer in the C program. for example, the ring_vmmath.c module contains the next code to register the module functions #include "ring.h" void ring_vm_math_loadfunctions ( RingState *pRingState ) { ring_vm_funcregister("sin",ring_vm_math_sin); ring_vm_funcregister("cos",ring_vm_math_cos); 82.3. Module Organization 915
  • 949.
    Ring Documentation, Release1.10 ring_vm_funcregister("tan",ring_vm_math_tan); ring_vm_funcregister("asin",ring_vm_math_asin); ring_vm_funcregister("acos",ring_vm_math_acos); ring_vm_funcregister("atan",ring_vm_math_atan); ring_vm_funcregister("atan2",ring_vm_math_atan2); ring_vm_funcregister("sinh",ring_vm_math_sinh); ring_vm_funcregister("cosh",ring_vm_math_cosh); ring_vm_funcregister("tanh",ring_vm_math_tanh); ring_vm_funcregister("exp",ring_vm_math_exp); ring_vm_funcregister("log",ring_vm_math_log); ring_vm_funcregister("log10",ring_vm_math_log10); ring_vm_funcregister("ceil",ring_vm_math_ceil); ring_vm_funcregister("floor",ring_vm_math_floor); ring_vm_funcregister("fabs",ring_vm_math_fabs); ring_vm_funcregister("pow",ring_vm_math_pow); ring_vm_funcregister("sqrt",ring_vm_math_sqrt); ring_vm_funcregister("unsigned",ring_vm_math_unsigned); ring_vm_funcregister("decimals",ring_vm_math_decimals); ring_vm_funcregister("murmur3hash",ring_vm_math_murmur3hash); } Tip: Remember that the function ring_vm_math_loadfunctions() will be called by the ring_vm_extension() function (in the ring_ext.c file). 82.4 Function Structure Each module function may contains the next steps 1 - Check Parameters Count 2 - Check Parameters Type 3 - Get Parameters Values 4 - Execute Code/Call Functions 5 - Return Value The structure is very similar to any function (Input - Process - Output) But here we will use the Ring API for the steps 1,2,3 and 5. 82.5 Check Parameters Count We can check the parameters count using the RING_API_PARACOUNT macro. We can compare RING_API_PARACOUNT with any numeric value using == or != operators. Example: if ( RING_API_PARACOUNT != 1 ) { /* code */ } Example: 82.4. Function Structure 916
  • 950.
    Ring Documentation, Release1.10 if ( RING_API_PARACOUNT == 1 ) { /* code */ } 82.6 Display Error Message We can display error messages using the RING_API_ERROR() function. The function will display the error and end the execution of the program. Note: the behaviour of this function can be changed by the Ring code using Try/Catch/Done statements, so in your C code, use Return after this function. Syntax: RING_API_ERROR(const char *cErrorMsg); The Ring API comes with some of predefined error messages that we can use #define RING_API_MISS1PARA "Bad parameters count, the function expect one parameter" #define RING_API_MISS2PARA "Bad parameters count, the function expect two parameters" #define RING_API_MISS3PARA "Bad parameters count, the function expect three parameters" #define RING_API_MISS4PARA "Bad parameters count, the function expect four parameters" #define RING_API_BADPARATYPE "Bad parameter type!" #define RING_API_BADPARACOUNT "Bad parameters count!" #define RING_API_BADPARARANGE "Bad parameters value, error in range!" #define RING_API_NOTPOINTER "Error in parameter, not pointer!" #define RING_API_NULLPOINTER "Error in parameter, NULL pointer!" #define RING_API_EMPTYLIST "Bad parameter, empty list!" 82.7 Check Parameters Type We can check the parameter type using the next functions int RING_API_ISNUMBER(int nParameterNumber); int RING_API_ISSTRING(int nParameterNumber); int RING_API_ISLIST(int nParameterNumber); int RING_API_ISPOINTER(int nParameterNumber); The output of these functions will be 1 (True) or 0 (False). 82.8 Get Parameters Values We can get paramters values using the next functions double RING_API_GETNUMBER(int nParameterNumber); const char *RING_API_GETSTRING(int nParameterNumber); int RING_API_GETSTRINGSIZE(int nParameterNumber); List *RING_API_GETLIST(int nParameterNumber); void *RING_API_GETCPOINTER(int nParameterNumber, const char *cPoinerType); int RING_API_GETPOINTERTYPE(int nParameterNumber); 82.6. Display Error Message 917
  • 951.
    Ring Documentation, Release1.10 82.9 Return Value We can return values from our function using the next functions. RING_API_RETNUMBER(double nValue); RING_API_RETSTRING(const char *cString); RING_API_RETSTRING2(const char *cString,int nStringSize); RING_API_RETLIST(List *pList); RING_API_RETCPOINTER(void *pValue,const char *cPointerType); RING_API_RETMANAGEDCPOINTER(void *pValue,const char *cPointerType, void (* pFreeFunc)(void *,void *)) 82.10 Function Prototype When we define new function to be used for RingVM extension, we use the next prototype void my_function_name( void *pPointer ); or we can use the RING_FUNC() Macro RING_FUNC(my_function_name); 82.11 Sin() Function Implementation The next code represents the sin() function implementation using the Ring API and the sin() C function. void ring_vm_math_sin ( void *pPointer ) { if ( RING_API_PARACOUNT != 1 ) { RING_API_ERROR(RING_API_MISS1PARA); return ; } if ( RING_API_ISNUMBER(1) ) { RING_API_RETNUMBER(sin(RING_API_GETNUMBER(1))); } else { RING_API_ERROR(RING_API_BADPARATYPE); } } 82.12 Fopen() and Fclose() Functions Implementation The next code represents the fopen() function implementation using the Ring API and the fopen() C Function. The function takes two parameters, the first parameter is the file name as string. The second parameter is the mode as string. In the file ring_vmfile.h we have some constants to use as the pointer type like #define RING_VM_POINTER_FILE "file" #define RING_VM_POINTER_FILEPOS "filepos" The function implementation in ring_vmfile.c 82.9. Return Value 918
  • 952.
    Ring Documentation, Release1.10 void ring_vm_file_fopen ( void *pPointer ) { FILE *fp ; if ( RING_API_PARACOUNT != 2 ) { RING_API_ERROR(RING_API_MISS2PARA); return ; } if ( RING_API_ISSTRING(1) && RING_API_ISSTRING(2) ) { fp = fopen(RING_API_GETSTRING(1),RING_API_GETSTRING(2)); RING_API_RETCPOINTER(fp,RING_VM_POINTER_FILE); } else { RING_API_ERROR(RING_API_BADPARATYPE); } } The next code represents the fclose() function implementation void ring_vm_file_fclose ( void *pPointer ) { FILE *fp ; if ( RING_API_PARACOUNT != 1 ) { RING_API_ERROR(RING_API_MISS1PARA); return ; } if ( RING_API_ISPOINTER(1) ) { fp = (FILE *) RING_API_GETCPOINTER(1,RING_VM_POINTER_FILE) ; if ( fp != NULL ) { RING_API_RETNUMBER(fclose(fp)); RING_API_SETNULLPOINTER(1); } } else { RING_API_ERROR(RING_API_BADPARATYPE); } } From fopen() and fclose() implementation we learned 1 - how to return C pointer using RING_API_RETCPOINTER() function 2 - how to check if the parameter is a pointer using the RING_API_ISPOINTER() function 3 - how to get C pointer value using the RING_API_GETCPOINTER() function 4 - how to set the C pointer variable (in RingVM) to NULL using the RING_API_SETNULLPOINTER() function 82.13 Ring API - List Functions In this section we will learn about the list functions provided by the Ring API to create new lists and manipulate the list items. List * ring_list_new ( int nSize ) ; void ring_list_newitem ( List *pList ) ; Item * ring_list_getitem ( List *pList,int index ) ; List * ring_list_delete ( List *pList ) ; void ring_list_deleteitem ( List *pList,int index ) ; void ring_list_print ( List *pList ) ; int ring_list_gettype ( List *pList, int index ) ; void ring_list_setint ( List *pList, int index ,int number ) ; 82.13. Ring API - List Functions 919
  • 953.
    Ring Documentation, Release1.10 void ring_list_addint ( List *pList,int x ) ; void ring_list_setpointer ( List *pList, int index ,void *pValue ) ; void ring_list_addpointer ( List *pList,void *pValue ) ; void ring_list_setfuncpointer ( List *pList, int index ,void (*pFunc)(void *) ) ; void ring_list_addfuncpointer ( List *pList,void (*pFunc)(void *) ) ; int ring_list_isfuncpointer ( List *pList, int index ) ; void ring_list_setdouble ( List *pList, int index ,double number ) ; void ring_list_adddouble ( List *pList,double x ) ; void ring_list_setstring ( List *pList, int index ,const char *str ) ; void ring_list_setstring2 ( List *pList, int index ,const char *str,int nStrSize ) ; void ring_list_addstring ( List *pList,const char *str ) ; void ring_list_addstring2 ( List *pList,const char *str,int nStrSize ) ; List * ring_list_newlist ( List *pList ) ; List * ring_list_getlist ( List *pList, int index ) ; void ring_list_setlist ( List *pList, int index ) ; void ring_list_setactiveitem ( List *pList, Items *pItems, int index ) ; void ring_list_copy ( List *pNewList, List *pList ) ; int ring_list_isnumber ( List *pList, int index ) ; int ring_list_isstring ( List *pList, int index ) ; int ring_list_islist ( List *pList, int index ) ; int ring_list_ispointer ( List *pList, int index ) ; void ring_list_deleteallitems ( List *pList ) ; void ring_list_insertitem ( List *pList,int x ) ; void ring_list_insertint ( List *pList,int nPos,int x ) ; void ring_list_insertdouble ( List *pList,int nPos,double x ) ; void ring_list_insertpointer ( List *pList,int nPos,void *pValue ) ; void ring_list_insertstring ( List *pList,int nPos,const char *str ) ; void ring_list_insertstring2 ( List *pList,int nPos,const char *str,int nStrSize ) ; void ring_list_insertfuncpointer ( List *pList,int nPos,void (*pFunc)(void *) ) ; List * ring_list_insertlist ( List *pList,int nPos ) ; int ring_list_isiteminsidelist ( List *pList,Item *pItem ) ; int ring_list_findstring ( List *pList,const char *str,int nColumn ) ; int ring_list_finddouble ( List *pList,double nNum1,int nColumn ) ; void ring_list_sortnum ( List *pList,int left,int right,int nColumn ) ; void ring_list_sortstr ( List *pList,int left,int right,int nColumn ) ; int ring_list_binarysearchnum ( List *pList,double nNum1,int nColumn ) ; int ring_list_binarysearchstr ( List *pList,const char *cFind,int nColumn ) ; void ring_list_swap ( List *pList,int x,int y ) ; double ring_list_getdoublecolumn ( List *pList,int nIndex,int nColumn ) ; char * ring_list_getstringcolumn ( List *pList,int nIndex,int nColumn ) ; void ring_list_genarray ( List *pList ) ; void ring_list_deletearray ( List *pList ) ; void ring_list_genhashtable ( List *pList ) ; void ring_list_genhashtable2 ( List *pList ) ; void ring_list_refcopy ( List *pNewList, List *pList ) ; void ring_list_clear ( List *pList ) ; /* Macro */ ring_list_isdouble(pList,index) ring_list_isint(pList,index) ring_list_deletelastitem(x) ring_list_gethashtable(x) ring_list_getint(pList,index) ring_list_getpointer(pList,index) ring_list_getfuncpointer(pList,index) ring_list_callfuncpointer(pList,index,x) ring_list_getdouble(pList,index) ring_list_getstring(pList,index) ring_list_getstringobject(pList,index) 82.13. Ring API - List Functions 920
  • 954.
    Ring Documentation, Release1.10 ring_list_getstringsize(pList,index) ring_list_getsize(x) (x->nSize) 82.14 Ring API - String Functions In this section we will learn about the string functions provided by the Ring API to create new string and manipulate the string content. String * ring_string_new ( const char *str ) ; String * ring_string_new2 ( const char *str,int nStrSize ) ; String * ring_string_delete ( String *pString ) ; int ring_string_size ( String *pString ) ; void ring_string_set ( String *pString,const char *str ) ; void ring_string_set2 ( String *pString,const char *str,int nStrSize ) ; void ring_string_add ( String *pString,const char *str ) ; void ring_string_add2 ( String *pString,const char *str,int nStrSize ) ; void ring_string_print ( String *pString ) ; void ring_string_setfromint ( String *pString,int x ) ; char * ring_string_lower ( char *cStr ) ; char * ring_string_upper ( char *cStr ) ; char * ring_string_lower2 ( char *cStr,int nStrSize ) ; char * ring_string_upper2 ( char *cStr,int nStrSize ) ; char * ring_string_find ( char *cStr1,char *cStr2 ) ; char * ring_string_find2 ( char *cStr1,int nStrSize1,char *cStr2,int nStrSize2 ) ; /* Macro */ ring_string_tolower(x) ring_string_toupper(x) ring_string_get(x) 82.15 MySQL_Columns() Function Implementation The next code presents the MySQL_Columns() function implementation. This function returns table columns information. void ring_vm_mysql_columns ( void *pPointer ) { MYSQL *con ; MYSQL_RES *result ; int nColumns,x ; MYSQL_ROW row ; MYSQL_FIELD *field ; List *pList, *pList2 ; if ( RING_API_PARACOUNT != 1 ) { RING_API_ERROR(RING_API_MISS1PARA); return ; } if ( RING_API_ISPOINTER(1) ) { con = (MYSQL *) RING_API_GETCPOINTER(1,RING_VM_POINTER_MYSQL) ; if ( con == NULL ) { return ; } result = mysql_store_result(con); if ( result == NULL ) { 82.14. Ring API - String Functions 921
  • 955.
    Ring Documentation, Release1.10 RING_API_RETNUMBER(0); return ; } pList = RING_API_NEWLIST ; nColumns = mysql_num_fields(result); if ( row = mysql_fetch_row(result) ) { while ( field = mysql_fetch_field(result) ) { pList2 = ring_list_newlist(pList); ring_list_addstring(pList2,field->name); ring_list_adddouble(pList2,field->length); ring_list_adddouble(pList2,field->type); ring_list_adddouble(pList2,field->flags); } } mysql_free_result(result); RING_API_RETLIST(pList); } else { RING_API_ERROR(RING_API_BADPARATYPE); } } Lists are of type List, in the previoud function we declared two pointers of type List using List *pList, *pList2; Note: The function uses RING_API_NEWLIST to create new list instead of ring_list_new() to create the list in Temp. Memory related to the function scope. This way we can return the list from the function. Also we don’t delete the list, if it’s stored in a variable by Ring Code it will be saved, if not it will be automatically deleted by RingVM. The list can contains sub lists, we used the function ring_list_newlist() to create a sublist. The function ring_list_addstring() is used to add string items to the list/sublist. The function ring_list_adddouble() is used to add numeric items to the list/sublist. Note: All numeric items in lists returned from RingVM extension functions must be of type double and added to the list using ring_list_adddouble() function. We return the list from the extension function using the RING_API_RETLIST() function. 82.16 Dynamic/Shared Libraries (DLL/So/Dylib) and LoadLib() func- tion Instead of rebuilding the RingVM after writing new functions using C/C++ and the Ring API, we can create a DLL/So/Dylib file and dynamically use the functions provided by this file in the runtime using the LoadLib() function. Dynamic library example in C #include "ring.h" RING_DLL __declspec(dllexport) RING_FUNC(ring_ringlib_dlfunc) { printf("Message from dlfunc"); } 82.16. Dynamic/Shared Libraries (DLL/So/Dylib) and LoadLib() function 922
  • 956.
    Ring Documentation, Release1.10 RING_DLL void ringlib_init(RingState *pRingState) { ring_vm_funcregister("dlfunc",ring_ringlib_dlfunc); } the idea is to create the ringlib_init() function, this function will be called by the RingVM when we use the generated DLL file though the LoadLib() function. Inside the ringlib_init() function we can register the module function or call a function that do the registration process for all of the module functions. The next Ring code demonstrates how to use the DLL library during the runtime. See "Dynamic DLL" + NL LoadLib("ringlib.dll") dlfunc() Output: Dynamic DLL Message from dlfunc 82.17 Using RING_API_RETMANAGEDCPOINTER() Using RING_API_RETMANAGEDCPOINTER() the Ring extensions written in C/C++ languages can return a man- aged pointer to Ring. This pointer can be controlled by the Ring VM using reference counting. This is important to avoid the need to write code that free the unmanaged resources like QPixMap objects in RingQt. Also the Code Generator for extensions is updated to automatically use RING_API_RETMANAGEDCPOINTER() based on need. Syntax: RING_API_RETMANAGEDCPOINTER(void *pValue,const char *cPointerType, void (* pFreeFunc)(void *,void *)) Example: The next example from ring_qt.cpp - QPixMap Class - Scaled() Method. RING_FUNC(ring_QPixmap_scaled) { QPixmap *pObject ; if ( RING_API_PARACOUNT != 5 ) { RING_API_ERROR(RING_API_BADPARACOUNT); return ; } RING_API_IGNORECPOINTERTYPE ; if ( ! RING_API_ISPOINTER(1) ) { RING_API_ERROR(RING_API_BADPARATYPE); return ; } pObject = (QPixmap *) RING_API_GETCPOINTER(1,"QPixmap"); if ( ! RING_API_ISNUMBER(2) ) { RING_API_ERROR(RING_API_BADPARATYPE); return ; } if ( ! RING_API_ISNUMBER(3) ) { 82.17. Using RING_API_RETMANAGEDCPOINTER() 923
  • 957.
    Ring Documentation, Release1.10 RING_API_ERROR(RING_API_BADPARATYPE); return ; } if ( ! RING_API_ISNUMBER(4) ) { RING_API_ERROR(RING_API_BADPARATYPE); return ; } if ( ! RING_API_ISNUMBER(5) ) { RING_API_ERROR(RING_API_BADPARATYPE); return ; } { QPixmap *pValue ; pValue = new QPixmap() ; *pValue = pObject->scaled( (int ) RING_API_GETNUMBER(2), (int ) RING_API_GETNUMBER(3), (Qt::AspectRatioMode ) (int) RING_API_GETNUMBER(4), (Qt::TransformationMode ) (int) RING_API_GETNUMBER(5)); RING_API_RETMANAGEDCPOINTER(pValue,"QPixmap",ring_QPixmap_freefunc); } } The function that will free the memory takes two parameters (Ring State and the allocated Memory Pointer) Example: void ring_QPixmap_freefunc(void *pState,void *pPointer) { QPixmap *pObject ; pObject = (QPixmap *) pPointer; delete pObject ; } 82.17. Using RING_API_RETMANAGEDCPOINTER() 924
  • 958.
    CHAPTER EIGHTYTHREE EMBEDDING RING LANGUAGEIN C/C++ PROGRAMS We can use the Ring language from C/C++ programs using the next functions RingState *ring_state_init(); ring_state_runcode(RingState *pState,const char *cCode); ring_state_delete(RingState *pState); 83.1 Ring State The idea is to use the ring_state_init() to create new state for the Ring Language then call the ring_state_runcode() function to execut Ring code using the same state. When we are done, we call the ring_state_delete() to free the memory. Example: #include "ring.h" #include "stdlib.h" int main(int argc, char *argv[]) { RingState *pState = ring_state_init(); printf("welcomen"); ring_state_runcode(pState,"see 'hello world from the ring programming language'+nl"); ring_state_delete(pState); } Output: welcome hello world from the ring programming language 83.2 Ring State Functions The Ring API comes with the next functions to create and delete the state. Also we have functions to create new variables and get variables values. RingState * ring_state_init ( void ) ; RingState * ring_state_delete ( RingState *pRingState ) ; void ring_state_runcode ( RingState *pRingState,const char *cStr ) ; List * ring_state_findvar ( RingState *pRingState,const char *cStr ) ; List * ring_state_newvar ( RingState *pRingState,const char *cStr ) ; void ring_state_main ( int argc, char *argv[] ) ; 925
  • 959.
    Ring Documentation, Release1.10 void ring_state_runfile ( RingState *pRingState,const char *cFileName ) ; void ring_state_runobjectfile ( RingState *pRingState,const char *cFileName ) ; 83.3 Ring State Variables We can create more than one ring state in the same program and we can create and modify variable values. To get the variable list we can use the ring_state_findvar() function. To create new variable we can use the ring_state_newvar() function. Example: #include "ring.h" #include "stdlib.h" int main(int argc, char *argv[]) { List *pList; RingState *pState = ring_state_init(); RingState *pState2 = ring_state_init(); printf("welcomen"); ring_state_runcode(pState,"see 'hello world from the ring programming language'+nl"); printf("Again from C we will call ring coden"); ring_state_runcode(pState,"for x = 1 to 10 see x + nl next"); ring_state_runcode(pState2,"for x = 1 to 5 see x + nl next"); printf("Now we will display the x variable value from ring coden"); ring_state_runcode(pState,"see 'x value : ' + x + nl "); ring_state_runcode(pState2,"see 'x value : ' + x + nl "); pList = ring_state_findvar(pState,"x"); printf("Printing Ring variable value from C , %.0fn", ring_list_getdouble(pList,RING_VAR_VALUE)); printf("now we will set the ring variable value from Cn"); ring_list_setdouble(pList,RING_VAR_VALUE,20); ring_state_runcode(pState,"see 'x value after update : ' + x + nl "); pList = ring_state_newvar(pState,"v1"); ring_list_setdouble(pList,RING_VAR_VALUE,10); pList = ring_state_newvar(pState,"v2"); ring_list_setdouble(pList,RING_VAR_VALUE,20); ring_state_runcode(pState,"see 'v1 + v2 = ' see v1+v2 see nl"); ring_state_runcode(pState,"see 'end of test' + nl"); ring_state_delete(pState); 83.3. Ring State Variables 926
  • 960.
    Ring Documentation, Release1.10 ring_state_delete(pState2); } Output: welcome hello world from the ring programming language Again from C we will call ring code 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 Now we will display the x variable value from ring code x value : 11 x value : 6 Printing Ring variable value from C , 11 now we will set the ring variable value from C x value after update : 20 v1 + v2 = 30 end of test 83.3. Ring State Variables 927
  • 961.
    CHAPTER EIGHTYFOUR CODE GENERATOR FORWRAPPING C/C++ LIBRARIES In this chapter we will learn how to use the code generator to wrap C/C++ Libraries to use it in our Ring applications. 84.1 Using the tool The code generator program is parsec.ring that can be executed as any ring code using the ring language. URL : https://github.com/ring-lang/ring/tree/master/extensions/codegen for example to read a configuration file called test.cf to generate the source code file test.c run parsec.ring as in the next command ring parsec.ring test.cf test.c 84.2 Configuration file The configuration file (*.cf) is the input file that we pass to the code generator. This file determine the functions prototypes that we need to use from a C/C++ library. Writing configuration files is simple according to the next rules 84.3 Using the function prototype • To generate code that wraps a C function, we just write the C function prototype Example: ALLEGRO_DISPLAY *al_create_display(int w, int h) void al_destroy_display(ALLEGRO_DISPLAY *display) int al_get_new_display_flags(void) void al_set_new_display_flags(int flags) int al_get_new_display_option(int option, int *importance) The previous example will guide the code generator to generate 5 functions that wraps the al_create_display(), al_destroy_display(), al_get_new_display_flags(), al_set_new_diplay_flas() and al_get_new_display_option() func- tions. The generated code will be as in the next example 928
  • 962.
    Ring Documentation, Release1.10 RING_FUNC(ring_al_create_display) { if ( RING_API_PARACOUNT != 2 ) { RING_API_ERROR(RING_API_MISS2PARA); return ; } if ( ! RING_API_ISNUMBER(1) ) { RING_API_ERROR(RING_API_BADPARATYPE); return ; } if ( ! RING_API_ISNUMBER(2) ) { RING_API_ERROR(RING_API_BADPARATYPE); return ; } RING_API_RETCPOINTER(al_create_display( (int ) RING_API_GETNUMBER(1), (int ) RING_API_GETNUMBER(2)),"ALLEGRO_DISPLAY"); } RING_FUNC(ring_al_destroy_display) { if ( RING_API_PARACOUNT != 1 ) { RING_API_ERROR(RING_API_MISS1PARA); return ; } if ( ! RING_API_ISPOINTER(1) ) { RING_API_ERROR(RING_API_BADPARATYPE); return ; } al_destroy_display((ALLEGRO_DISPLAY *) RING_API_GETCPOINTER(1,"ALLEGRO_DISPLAY")); } RING_FUNC(ring_al_get_new_display_flags) { if ( RING_API_PARACOUNT != 0 ) { RING_API_ERROR(RING_API_BADPARACOUNT); return ; } RING_API_RETNUMBER(al_get_new_display_flags()); } RING_FUNC(ring_al_set_new_display_flags) { if ( RING_API_PARACOUNT != 1 ) { RING_API_ERROR(RING_API_MISS1PARA); return ; } if ( ! RING_API_ISNUMBER(1) ) { RING_API_ERROR(RING_API_BADPARATYPE); return ; } al_set_new_display_flags( (int ) RING_API_GETNUMBER(1)); } RING_FUNC(ring_al_get_new_display_option) 84.3. Using the function prototype 929
  • 963.
    Ring Documentation, Release1.10 { if ( RING_API_PARACOUNT != 2 ) { RING_API_ERROR(RING_API_MISS2PARA); return ; } if ( ! RING_API_ISNUMBER(1) ) { RING_API_ERROR(RING_API_BADPARATYPE); return ; } if ( ! RING_API_ISSTRING(2) ) { RING_API_ERROR(RING_API_BADPARATYPE); return ; } RING_API_RETNUMBER(al_get_new_display_option( (int ) RING_API_GETNUMBER(1), RING_API_GETINTPOINTER(2))); RING_API_ACCEPTINTVALUE(2) ; } from the previous example we can see how much of time and effort is saved using the Code Generator. 84.4 Adding code to the generated code • To generate code directly type it between <code> and </code> Example : <code> /* some C code will be written here */ </code> We use this feature when we need to do something without the help of the code generator. for example including header files and defining constants using Macro. 84.5 Prefix for Functions Names • To determine a prefix in all of the functions names type it between <funcstart> and </funcstart> for ex- ample when we wrap the Allegro game programming library and we need all of the library functions to start with “al” we type the next code in the configuration file <funcstart> al </funcstart> 84.6 Generate function to wrap structures • To generate functions that wrap structures (create/delete/get structure members) just type the structures names between <struct> and </struct> also after the structure name you can type the structure members between { } separated by comma. Example 84.4. Adding code to the generated code 930
  • 964.
    Ring Documentation, Release1.10 <struct> ALLEGRO_COLOR ALLEGRO_EVENT { type , keyboard.keycode , mouse.x , mouse.y } </struct> from the previous example we will generate two function to create/delete the structure ALLEGRO_COLOR Also we will generate two functions to create/delete the structure ALLEGRO_EVENT and four functions to get the structure ALLEGRO_EVENT members (type, keyboard.keycode, mouse.x, mouse.y). 84.7 Determine Structure Members Types You can determine the pointer name before the strucuture member name. Example: SDL_Surface {flags,SDL_PixelFormat *format,w,h,pitch,void *pixels} 84.8 Defining Constants You can define constants using <constant> and </constant> The generator will generate the required functions to get the constant values And will define the constants to be used with the same name in Ring code using *.rh file that will be generated too. rh = Ring Header Example: <constant> MIX_DEFAULT_FORMAT SDL_QUIT SDL_BUTTON_LEFT SDL_BUTTON_MIDDLE SDL_BUTTON_RIGHT </constant> Note: You will need to pass the *.rh file name to parsec.ring after the generated source file name. Example: ring ..codegenparsec.ring libsdl.cf ring_libsdl.c ring_libsdl.rh 84.9 Register New Functions We can register functions by typing the function prototype between <register> and </register> We need this feature only when we don’t provide the function prototype as input directly where we need to write the code of this function. Example: <register> void al_exit(void) </register> 84.7. Determine Structure Members Types 931
  • 965.
    Ring Documentation, Release1.10 <code> RING_FUNC(ring_al_exit) { if ( RING_API_PARACOUNT != 0 ) { RING_API_ERROR(RING_API_BADPARACOUNT); return ; } exit(0); } </code> In the previous example we register the al_exit() function. This function is