<commit_before>/*
 * Copyright 2016 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {LayerGroup, MaskLayer, PathLayer} from 'model';
import {ColorUtil} from 'colorutil';
import {ElementResizeWatcher} from 'elementresizewatcher';


const CANVAS_MARGIN = 72; // pixels


class CanvasController {
  constructor($scope, $element, $attrs, StudioStateService, $timeout) {
    this.scope_ = $scope;
    this.element_ = $element;
    this.attrs_ = $attrs;
    this.canvas_ = $element.find('canvas');
    this.offscreenCanvas_ = $(document.createElement('canvas'));
    this.studioState_ = StudioStateService;
    this.registeredRulers_ = [];

    this.isPreviewMode = 'previewMode' in $attrs;
    if (this.isPreviewMode) {
      this.element_.addClass('preview-mode');
    }

    this.setupMouseEventHandlers_();

    let changeHandler_ = (event, changes) => {
      if (changes.playing) {
        if (this.studioState_.playing) {
          this.animStart = Number(new Date())
              - this.studioState_.activeTime / this.studioState_.playbackSpeed;
        }

        this.drawCanvas_();
      }

      if (changes.activeTime) {
        this.animTime = this.studioState_.activeTime;
        this.drawCanvas_();
      }

      if (changes.selection) {
        this.drawCanvas_();
      }

      if (changes.artwork || changes.animations || changes.activeAnimation) {
        this.resizeAndDrawCanvas_();
      }
    };

    changeHandler_(null, {playing: true, activeTime: true, artwork: true});

    this.studioState_.onChange(changeHandler_, $scope);

    if (!this.isPreviewMode) {
      let resizeWatcher = new ElementResizeWatcher(
          this.element_, () => this.resizeAndDrawCanvas_());
      $scope.$on('$destroy', () => resizeWatcher.destroy());
    }

    $timeout(() => this.resizeAndDrawCanvas_(), 0);
  }

  setupMouseEventHandlers_() {
    this.canvas_
        .on('mousedown', event => {
          let canvasOffset = this.canvas_.offset();
          let x = (event.pageX - canvasOffset.left) / this.scale_;
          let y = (event.pageY - canvasOffset.top) / this.scale_;
          let matrices = [];
          // TODO(alockwood): select clips and/or groups in addition to paths?
          let toggleSelectedPath_ = layer => {
            if (layer instanceof LayerGroup) {
              let transformMatrices = this.createTransformMatrices_(layer);
              matrices.splice(matrices.length, 0, ...transformMatrices);
              let result = layer.layers.some(layer => toggleSelectedPath_(layer));
              matrices.splice(-transformMatrices.length, transformMatrices.length);
              return result;
            } else if (layer instanceof PathLayer && layer.pathData) {
              let shouldUpdateSelection = false;
              let transformedMouseDownPoint =
                  this.transformPoint_({x, y}, Array.from(matrices).reverse());
              if (layer.fillColor) {
                shouldUpdateSelection =
                    layer.pathData.isFillSelected(transformedMouseDownPoint);
              } else if (layer.strokeColor) {
                shouldUpdateSelection =
                    layer.pathData.isStrokeSelected(transformedMouseDownPoint, layer.strokeWidth);
              }
              if (shouldUpdateSelection) {
                if (event.metaKey || event.shiftKey) {
                  this.studioState_.toggleSelected(layer);
                } else {
                  this.studioState_.selection = [layer];
                }
                return true;
              }
              return false;
            }
            return false;
          };
          if (!toggleSelectedPath_(this.artwork) && !(event.metaKey || event.shiftKey)) {
            this.studioState_.selection = [];
          }
        })
        .on('mousemove', event => {
          let canvasOffset = this.canvas_.offset();
          let x = Math.round((event.pageX - canvasOffset.left) / this.scale_);
          let y = Math.round((event.pageY - canvasOffset.top) / this.scale_);
          this.registeredRulers_.forEach(r => r.showMousePosition(x, y));
        })
        .on('mouseleave', () => {
          this.registeredRulers_.forEach(r => r.hideMouse());
        });
  }

  get artwork() {
    return this.studioState_.artwork;
  }

  get animation() {
    return this.studioState_.activeAnimation;
  }

  registerRuler(rulerScope) {
    this.registeredRulers_.push(rulerScope);
    this.redrawRulers_();
  }
<commit_msg>simplify recursive loop<commit_after>/*
 * Copyright 2016 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {LayerGroup, MaskLayer, PathLayer} from 'model';
import {ColorUtil} from 'colorutil';
import {ElementResizeWatcher} from 'elementresizewatcher';


const CANVAS_MARGIN = 72; // pixels


class CanvasController {
  constructor($scope, $element, $attrs, StudioStateService, $timeout) {
    this.scope_ = $scope;
    this.element_ = $element;
    this.attrs_ = $attrs;
    this.canvas_ = $element.find('canvas');
    this.offscreenCanvas_ = $(document.createElement('canvas'));
    this.studioState_ = StudioStateService;
    this.registeredRulers_ = [];

    this.isPreviewMode = 'previewMode' in $attrs;
    if (this.isPreviewMode) {
      this.element_.addClass('preview-mode');
    }

    this.setupMouseEventHandlers_();

    let changeHandler_ = (event, changes) => {
      if (changes.playing) {
        if (this.studioState_.playing) {
          this.animStart = Number(new Date())
              - this.studioState_.activeTime / this.studioState_.playbackSpeed;
        }

        this.drawCanvas_();
      }

      if (changes.activeTime) {
        this.animTime = this.studioState_.activeTime;
        this.drawCanvas_();
      }

      if (changes.selection) {
        this.drawCanvas_();
      }

      if (changes.artwork || changes.animations || changes.activeAnimation) {
        this.resizeAndDrawCanvas_();
      }
    };

    changeHandler_(null, {playing: true, activeTime: true, artwork: true});

    this.studioState_.onChange(changeHandler_, $scope);

    if (!this.isPreviewMode) {
      let resizeWatcher = new ElementResizeWatcher(
          this.element_, () => this.resizeAndDrawCanvas_());
      $scope.$on('$destroy', () => resizeWatcher.destroy());
    }

    $timeout(() => this.resizeAndDrawCanvas_(), 0);
  }

  setupMouseEventHandlers_() {
    this.canvas_
        .on('mousedown', event => {
          let canvasOffset = this.canvas_.offset();
          let x = (event.pageX - canvasOffset.left) / this.scale_;
          let y = (event.pageY - canvasOffset.top) / this.scale_;
          let matrices = [];
          // TODO(alockwood): select clips and/or groups in addition to paths?
          let toggleSelectedPath_ = layer => {
            if (layer instanceof LayerGroup) {
              let transformMatrices = this.createTransformMatrices_(layer);
              matrices.splice(matrices.length, 0, ...transformMatrices);
              let result = layer.layers.some(layer => toggleSelectedPath_(layer));
              matrices.splice(-transformMatrices.length, transformMatrices.length);
              return result;
            } else if (layer instanceof PathLayer && layer.pathData) {
              let shouldUpdateSelection = false;
              let transformedMouseDownPoint =
                  this.transformPoint_({x, y}, Array.from(matrices).reverse());
              if (layer.fillColor) {
                shouldUpdateSelection =
                    layer.pathData.isFillSelected(transformedMouseDownPoint);
              } else if (layer.strokeColor) {
                shouldUpdateSelection =
                    layer.pathData.isStrokeSelected(transformedMouseDownPoint, layer.strokeWidth);
              }
              if (shouldUpdateSelection) {
                if (event.metaKey || event.shiftKey) {
                  this.studioState_.toggleSelected(layer);
                } else {
                  this.studioState_.selection = [layer];
                }
              }
              return shouldUpdateSelection;
            }
            return false;
          };
          if (!toggleSelectedPath_(this.artwork) && !(event.metaKey || event.shiftKey)) {
            this.studioState_.selection = [];
          }
        })
        .on('mousemove', event => {
          let canvasOffset = this.canvas_.offset();
          let x = Math.round((event.pageX - canvasOffset.left) / this.scale_);
          let y = Math.round((event.pageY - canvasOffset.top) / this.scale_);
          this.registeredRulers_.forEach(r => r.showMousePosition(x, y));
        })
        .on('mouseleave', () => {
          this.registeredRulers_.forEach(r => r.hideMouse());
        });
  }

  get artwork() {
    return this.studioState_.artwork;
  }

  get animation() {
    return this.studioState_.activeAnimation;
  }

  registerRuler(rulerScope) {
    this.registeredRulers_.push(rulerScope);
    this.redrawRulers_();
  }

{'fraction_non_alphanumeric': 0.11515030460401478, 'fraction_numerical': 0.0023968840507340456, 'mean_word_length': 2.3547738693467335, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5913732', 'n_tokens_mistral': 2790, 'n_tokens_neox': 2694, 'n_words': 606}