layout_recipe_base.php 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. <?php
  2. /*
  3. Abstract base class for an object which generates a layout for your course.
  4. */
  5. class SloodleLayoutRecipe {
  6. var $_rowsets = array();
  7. var $_course;
  8. // over-ride this function to specify a title for the recipe which can be shown to the user.
  9. function title() {
  10. }
  11. // over-ride this function to make the class actually do something useful.
  12. function generate() {
  13. }
  14. function setCourse($course) {
  15. $this->_course = $course;
  16. }
  17. function addRowSet( $rowset ) {
  18. $this->_rowsets[] = $rowset;
  19. }
  20. // Return an array with course module ids as keys and object names as values
  21. function objectsByCourseModule( $objectnames = null ) {
  22. $moduleObjectDefinitions = array();
  23. foreach ($objectnames as $objn) {
  24. $objdefn = SloodleObjectConfig::ForObjectName( $objn );
  25. if (!$objdefn) { // object not found
  26. continue;
  27. }
  28. if (!$module = $objdefn->module) { // no module needed for this object
  29. continue;
  30. }
  31. if ( !isset( $moduleObjectDefinitions[ $module ] ) ) {
  32. $moduleObjectDefinitions[ $module ] = array();
  33. }
  34. $moduleObjectDefinitions[ $module ][] = $objdefn;
  35. }
  36. $delim = '';
  37. $params = array();
  38. $instr = '';
  39. foreach( $moduleObjectDefinitions as $module => $defns ) {
  40. $instr .= $delim.'?';
  41. $params[] = $module;
  42. $delim = ',';
  43. }
  44. global $CFG;
  45. $sql = "select cm.id as id, cm.instance as instance, m.name as module_name from {$CFG->prefix}modules m inner join {$CFG->prefix}course_modules cm on m.id=cm.module where m.name in( $instr ) AND cm.visible = 1;";
  46. $recs = sloodle_get_records_sql_params( $sql, $params );
  47. if (!$recs) {
  48. return false;
  49. }
  50. $objectsByCourseModule = array();
  51. foreach ($recs as $cm) {
  52. $defns = $moduleObjectDefinitions[ $cm->module_name ];
  53. $instance = null;
  54. foreach($defns as $defn) {
  55. $skip = false;
  56. // Filter by instance if there are module_filters - otherwise we can add the object without bothering to fetch the module instance
  57. if ( (is_array($defn->module_filters)) && (count($defn->module_filters) > 0) ) {
  58. if (!$instance) {
  59. $instance = sloodle_get_record($cm->module_name, 'id', $cm->instance);
  60. }
  61. foreach($defn->module_filters as $n => $v) {
  62. if ( (!isset($instance->n)) || ($instance->$n != $v) ) {
  63. $skip = true;
  64. break;
  65. }
  66. }
  67. }
  68. if (!$skip) {
  69. $objectsByCourseModule[ $cm->id ][] = $defn;
  70. }
  71. }
  72. }
  73. return $objectsByCourseModule;
  74. }
  75. function saveToLayoutWithID( $layoutid ) {
  76. $layout = new SloodleLayout();
  77. if (!$layout->load($layoutid)) {
  78. return false;
  79. }
  80. foreach( $this->_rowsets as $rowset ) {
  81. foreach( $rowset->getRows() as $row ) {
  82. if ($entries = $row->getEntries() ) {
  83. foreach($entries as $entry ) {
  84. $layout->add_entry( $entry );
  85. }
  86. }
  87. }
  88. }
  89. return $layout->update();
  90. }
  91. function addObjectAtPoint( $name, $cmid = null, $params = null, $x = 0, $y = 0, $z = 0, $rotation = "<0,0,0,0>" ) {
  92. $objpoint = SloodleLayoutRowSet::Point( $x, $y, $z, $rotation );
  93. if ( $objpoint->addEntryByName( $name, $cmid, $params ) ) {
  94. return $this->addRowSet( $objpoint );
  95. } else {
  96. print "add failed";
  97. }
  98. return false;
  99. }
  100. }
  101. class SloodleSimpleLayoutRecipe extends SloodleLayoutRecipe {
  102. function title() {
  103. return 'Simple Two-Row Layout';
  104. }
  105. function generate() {
  106. // Plonk a LoginZone overhead
  107. $this->addObjectAtPoint( 'SLOODLE LoginZone', $cmid = null, $params = null, $x = 0, $y = 0, $z = 10 );
  108. // Make a simple layout with one long row on each side
  109. // Fill it up as we go, so when the left one is full we start putting things in the right one
  110. $rowset = new SloodleLayoutRowSet();
  111. $leftrow = new SloodleLayoutRow();
  112. $leftrow->setPosition( $x = -5, $y = 1, $z = 1 ); // make a row starting at the left of the rezzer
  113. $leftrow->setDimensions( $x = 0, $y = 10, $z = 0 );
  114. $leftrow->setSpacing( $x = 0, $y = -2, $z = 0 );
  115. $leftrow->setDefaultRotation( "<0,0,0,0>" );
  116. $rowset->addRow( $leftrow );
  117. $rightrow = new SloodleLayoutRow();
  118. $rightrow->setPosition( $x = 5, $y = 1, $z = 1 ); // make a row starting at the right of the rezzer
  119. $rightrow->setDimensions( $x = 0, $y = 10, $z = 0 );
  120. $rightrow->setSpacing( $x = 0, $y = -2, $z = 0 );
  121. $rightrow->setDefaultRotation( "<0,0,0,0>" );
  122. $rowset->addRow( $rightrow );
  123. // Give the row a RegEnrol booth and a Password Reset
  124. $rowset->addEntryByName( 'SLOODLE RegEnrol Booth' );
  125. $rowset->addEntryByName( 'SLOODLE Password Reset' );
  126. // Keep filling out the space with a WebIntercom and a QuizChair for each coursemodule
  127. // eg. If we have one chatroom and two quizzes, we'll get one WebIntercom and two QuizChairs, one for each quiz.
  128. $moduleObjects = $this->objectsByCourseModule(
  129. array(
  130. 'SLOODLE WebIntercom',
  131. 'SLOODLE QuizChair',
  132. 'SLOODLE MetaGloss',
  133. 'SLOODLE Choice (Horizontal)',
  134. 'SLOODLE Presenter',
  135. 'SLOODLE Vending Machine',
  136. 'SLOODLE PrimDrop',
  137. )
  138. );
  139. foreach( $moduleObjects as $cmid => $objdefns) {
  140. foreach($objdefns as $defn) {
  141. if (!$defn) {
  142. continue;
  143. }
  144. if (!$defn->primname) {
  145. continue;
  146. }
  147. $objname = $defn->primname;
  148. $rowset->addEntryByName( $objname, $cmid );
  149. }
  150. }
  151. $this->addRowSet( $rowset );
  152. return true;
  153. }
  154. }
  155. /*
  156. Class representing a set of rows in which objects can be placed.
  157. */
  158. class SloodleLayoutRowSet {
  159. var $_rows = array();
  160. var $_rowIndex = 0;
  161. // Static method returning a SloodleLayoutRowSet instance consisting of a single row for a single object.
  162. // Use this when you want to add a single object, and you know exactly where you want to put it.
  163. // Allows you to place an object in a single function call, without all the rest of the RowSet bureaucracy.
  164. function Point( $x, $y, $z, $rotation = "<0,0,0,0>" ) {
  165. $row = new SloodleLayoutRow();
  166. $row->setPosition( $x, $y, $z );
  167. $row->setDimensions( $x = 1, $y = 1, $z = 1 );
  168. $row->setSpacing( $x = 0, $y = 0, $z = 0 );
  169. $row->setDefaultRotation( $rotation );
  170. $rs = new SloodleLayoutRowSet();
  171. $rs->addRow( $row );
  172. return $rs;
  173. }
  174. // Adds a SloodleLayoutRow instance to the set
  175. function addRow( $row ) {
  176. $this->_rows[] = $row;
  177. }
  178. function getRows() {
  179. return $this->_rows;
  180. }
  181. // Creates an entry for the specified name and parameters, then adds it (see addEntry).
  182. // Returns false if it can't create the entry, or if addEntry() fails to add it.
  183. function addEntryByName( $name, $cmid = null, $params = null ) {
  184. if ( !$entry = SloodleLayoutEntry::ForConfig($name) ) {
  185. return false;
  186. }
  187. if ($cmid) {
  188. $entry->set_config('sloodlemoduleid', $cmid);
  189. }
  190. if ($params) {
  191. foreach($params as $n => $v) {
  192. $entry->setConfig( $n, $v );
  193. }
  194. }
  195. return $this->addEntry( $entry );
  196. }
  197. // Adds the entry to the next space in the first available row if there's room for it, returns false if there isn't.
  198. function addEntry( $entry ) {
  199. if ( $this->_rowIndex >= count($this->_rows) ) {
  200. return false;
  201. }
  202. $currentRow = $this->_rows[ $this->_rowIndex ];
  203. // Trying to add the entry to the current row
  204. // If that fails, go to the next row and try again
  205. // If we run out of rows to try, give up and return false.
  206. while ( !$currentRow->addEntry( $entry ) ) {
  207. $this->_rowIndex++;
  208. if ( $this->_rowIndex >= count($this->_rows) ) {
  209. return false;
  210. }
  211. $currentRow = $this->_rows[ $this->_rowIndex ];
  212. }
  213. return true;
  214. }
  215. }
  216. class SloodleLayoutRow {
  217. // For setting all the objects in the row to face the same way.
  218. // In practice we'll probably want them to face towards a central position, which involves some difficult position maths, unless we do it on the LSL side.
  219. var $_defaultRotation = null;
  220. var $_spacingx = 0;
  221. var $_spacingy = 0;
  222. var $_spacingz = 0;
  223. var $_posx = 0;
  224. var $_posy = 0;
  225. var $_posz = 0;
  226. var $_dimx = 0;
  227. var $_dimy = 0;
  228. var $_dimz = 0;
  229. var $_lastposx = 0;
  230. var $_lastposy = 0;
  231. var $_lastposz = 0;
  232. var $_entries = array();
  233. // Adds the entry to the next space in the row if there's room for it, returns false if there isn't.
  234. function addEntry( $entry ) {
  235. if ( !$posarr = $this->nextPosition() ) {
  236. return false;
  237. }
  238. $x = $this->_posx + $posarr['x'];
  239. $y = $this->_posy + $posarr['y'];
  240. $z = $this->_posz + $posarr['z'];
  241. $entry->position = "<$x,$y,$z>";
  242. $entry->rotation = $this->_defaultRotation;
  243. $this->_entries[] = $entry;
  244. return true;
  245. }
  246. function setDefaultRotation( $rot ) {
  247. $this->_defaultRotation = $rot;
  248. }
  249. function setSpacing( $x, $y, $z ) {
  250. $this->_spacingx = $x;
  251. $this->_spacingy = $y;
  252. $this->_spacingz = $z;
  253. }
  254. // Position of the row
  255. function setPosition( $x, $y, $z ) {
  256. $this->_posx = $x;
  257. $this->_posy = $y;
  258. $this->_posz = $z;
  259. }
  260. // Dimensions of the row
  261. function setDimensions( $x = 0, $y = 0, $z = 0 ) {
  262. $this->_dimx = $x;
  263. $this->_dimy = $y;
  264. $this->_dimz = $z;
  265. }
  266. // Returns an array representing the next available position within the row
  267. // NB This is relative to the row, so it needs to be added to the row position to get a position relative to the rezzer
  268. function nextPosition() {
  269. $x = $this->_lastposx + $this->_spacingx;
  270. $y = $this->_lastposy + $this->_spacingy;
  271. $z = $this->_lastposz + $this->_spacingz;
  272. if ( ($x > $this->_dimx) || ($y > $this->_dimy) || ($y > $this->_dimy) ) {
  273. return false; // Full
  274. }
  275. $this->_lastposx = $x;
  276. $this->_lastposy = $y;
  277. $this->_lastposz = $z;
  278. return array( 'x' => $x, 'y' => $y, 'z' => $z );
  279. }
  280. function getEntries() {
  281. return $this->_entries;
  282. }
  283. }
  284. ?>