<commit_before>/*
 * Copyright (C) 2019 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.
 */
package com.google.gapid.perfetto;

import static com.google.gapid.perfetto.views.StyleConstants.KB_DELAY;
import static com.google.gapid.perfetto.views.StyleConstants.KB_PAN_FAST;
import static com.google.gapid.perfetto.views.StyleConstants.KB_PAN_SLOW;
import static com.google.gapid.perfetto.views.StyleConstants.KB_ZOOM_FAST;
import static com.google.gapid.perfetto.views.StyleConstants.KB_ZOOM_SLOW;
import static com.google.gapid.perfetto.views.StyleConstants.ZOOM_FACTOR_SCALE;

import com.google.gapid.models.Capture;
import com.google.gapid.models.Models;
import com.google.gapid.models.Perfetto;
import com.google.gapid.perfetto.canvas.Area;
import com.google.gapid.perfetto.canvas.PanelCanvas;
import com.google.gapid.perfetto.models.Selection;
import com.google.gapid.perfetto.views.RootPanel;
import com.google.gapid.perfetto.views.SelectionView;
import com.google.gapid.perfetto.views.State;
import com.google.gapid.util.Keyboard;
import com.google.gapid.util.Loadable;
import com.google.gapid.widgets.LoadablePanel;
import com.google.gapid.widgets.Widgets;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.ScrollBar;

/**
 * The main entry point of the Perfetto trace UI.
 */
public class TraceView extends Composite
    implements Capture.Listener, Perfetto.Listener, State.Listener {
  private final Models models;
  private final State state;
  private final LoadablePanel<SashForm> loading;
  private final RootPanel rootPanel;
  private final PanelCanvas canvas;

  public TraceView(Composite parent, Models models, Widgets widgets) {
    super(parent, SWT.NONE);
    this.models = models;
    this.state = new State(this);

    setLayout(new FillLayout());

    loading = new LoadablePanel<SashForm>(this, widgets, p -> new SashForm(p, SWT.VERTICAL));
    SashForm topBottom = loading.getContents();
    rootPanel = new RootPanel(state);
    canvas = new PanelCanvas(topBottom, SWT.H_SCROLL, widgets.theme, rootPanel);
    new SelectionView(topBottom, state);
    topBottom.setWeights(models.settings.perfettoSplitterWeights);

    canvas.addListener(SWT.MouseWheel, e -> {
      if ((e.stateMask & SWT.MODIFIER_MASK) == SWT.MOD1) {
        e.doit = false;
        if (rootPanel.zoom(e.x, 1.0 - Math.max(-3, Math.min(3, e.count)) * ZOOM_FACTOR_SCALE)) {
          canvas.redraw(Area.FULL, true);
        }
      }
    });
    canvas.addListener(SWT.MouseHorizontalWheel, e -> {
      if ((e.stateMask & SWT.MODIFIER_MASK) == SWT.MOD1) {
        // Ignore horizontal scroll, only when zooming.
        e.doit = false;
      }
    });
    canvas.addListener(SWT.Gesture, this::handleGesture);
    canvas.getHorizontalBar().addListener(SWT.Selection, e -> {
      TimeSpan trace = state.getTraceTime();
      int sel = canvas.getHorizontalBar().getSelection();
      if (state.scrollToX(trace.start + sel * trace.getDuration() / 10000)) {
        canvas.redraw(Area.FULL, true);
      }
    });
    canvas.getVerticalBar().addListener(SWT.Selection, e -> {
      int sel = canvas.getVerticalBar().getSelection();
      if (state.scrollToY(sel)) {
        canvas.redraw(Area.FULL, true);
      }
    });
    new Keyboard(canvas, KB_DELAY, kb -> {
      boolean redraw = false;
      boolean fast = kb.isKeyDown(SWT.SHIFT);
      if (kb.isKeyDown('a') || kb.isKeyDown(SWT.ARROW_LEFT)) {
        redraw = state.dragX(state.getVisibleTime(), fast ? KB_PAN_FAST : KB_PAN_SLOW) || redraw;
      } else if (kb.isKeyDown('d') || kb.isKeyDown(SWT.ARROW_RIGHT)) {
        redraw = state.dragX(state.getVisibleTime(), -(fast ? KB_PAN_FAST : KB_PAN_SLOW)) || redraw;
      }

      if (kb.isKeyDown('w') || kb.isKeyDown(SWT.ARROW_UP)) {
        redraw = state.dragY(fast ? KB_PAN_FAST : KB_PAN_SLOW) || redraw;
      } else if (kb.isKeyDown('s') || kb.isKeyDown(SWT.ARROW_DOWN)) {
        redraw = state.dragY(-(fast ? KB_PAN_FAST : KB_PAN_SLOW)) || redraw;
      }

      if (kb.isKeyDown('q')) {
        Point mouse = canvas.toControl(getDisplay().getCursorLocation());
        redraw = rootPanel.zoom(mouse.x, 1.0 - (fast ? KB_ZOOM_FAST : KB_ZOOM_SLOW)) || redraw;
      } else if (kb.isKeyDown('e')) {
        Point mouse = canvas.toControl(getDisplay().getCursorLocation());
        redraw = rootPanel.zoom(mouse.x, 1.0 + (fast ? KB_ZOOM_FAST : KB_ZOOM_SLOW)) || redraw;
      }

      if (kb.isKeyDown('m')) {
        Selection selection = state.getSelection();
        if (selection != null) {<commit_msg>W/S now zooms instead of Q/E.<commit_after>/*
 * Copyright (C) 2019 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.
 */
package com.google.gapid.perfetto;

import static com.google.gapid.perfetto.views.StyleConstants.KB_DELAY;
import static com.google.gapid.perfetto.views.StyleConstants.KB_PAN_FAST;
import static com.google.gapid.perfetto.views.StyleConstants.KB_PAN_SLOW;
import static com.google.gapid.perfetto.views.StyleConstants.KB_ZOOM_FAST;
import static com.google.gapid.perfetto.views.StyleConstants.KB_ZOOM_SLOW;
import static com.google.gapid.perfetto.views.StyleConstants.ZOOM_FACTOR_SCALE;

import com.google.gapid.models.Capture;
import com.google.gapid.models.Models;
import com.google.gapid.models.Perfetto;
import com.google.gapid.perfetto.canvas.Area;
import com.google.gapid.perfetto.canvas.PanelCanvas;
import com.google.gapid.perfetto.models.Selection;
import com.google.gapid.perfetto.views.RootPanel;
import com.google.gapid.perfetto.views.SelectionView;
import com.google.gapid.perfetto.views.State;
import com.google.gapid.util.Keyboard;
import com.google.gapid.util.Loadable;
import com.google.gapid.widgets.LoadablePanel;
import com.google.gapid.widgets.Widgets;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.ScrollBar;

/**
 * The main entry point of the Perfetto trace UI.
 */
public class TraceView extends Composite
    implements Capture.Listener, Perfetto.Listener, State.Listener {
  private final Models models;
  private final State state;
  private final LoadablePanel<SashForm> loading;
  private final RootPanel rootPanel;
  private final PanelCanvas canvas;

  public TraceView(Composite parent, Models models, Widgets widgets) {
    super(parent, SWT.NONE);
    this.models = models;
    this.state = new State(this);

    setLayout(new FillLayout());

    loading = new LoadablePanel<SashForm>(this, widgets, p -> new SashForm(p, SWT.VERTICAL));
    SashForm topBottom = loading.getContents();
    rootPanel = new RootPanel(state);
    canvas = new PanelCanvas(topBottom, SWT.H_SCROLL, widgets.theme, rootPanel);
    new SelectionView(topBottom, state);
    topBottom.setWeights(models.settings.perfettoSplitterWeights);

    canvas.addListener(SWT.MouseWheel, e -> {
      if ((e.stateMask & SWT.MODIFIER_MASK) == SWT.MOD1) {
        e.doit = false;
        if (rootPanel.zoom(e.x, 1.0 - Math.max(-3, Math.min(3, e.count)) * ZOOM_FACTOR_SCALE)) {
          canvas.redraw(Area.FULL, true);
        }
      }
    });
    canvas.addListener(SWT.MouseHorizontalWheel, e -> {
      if ((e.stateMask & SWT.MODIFIER_MASK) == SWT.MOD1) {
        // Ignore horizontal scroll, only when zooming.
        e.doit = false;
      }
    });
    canvas.addListener(SWT.Gesture, this::handleGesture);
    canvas.getHorizontalBar().addListener(SWT.Selection, e -> {
      TimeSpan trace = state.getTraceTime();
      int sel = canvas.getHorizontalBar().getSelection();
      if (state.scrollToX(trace.start + sel * trace.getDuration() / 10000)) {
        canvas.redraw(Area.FULL, true);
      }
    });
    canvas.getVerticalBar().addListener(SWT.Selection, e -> {
      int sel = canvas.getVerticalBar().getSelection();
      if (state.scrollToY(sel)) {
        canvas.redraw(Area.FULL, true);
      }
    });
    new Keyboard(canvas, KB_DELAY, kb -> {
      boolean redraw = false;
      boolean fast = kb.isKeyDown(SWT.SHIFT);
      if (kb.isKeyDown('a') || kb.isKeyDown(SWT.ARROW_LEFT)) {
        redraw = state.dragX(state.getVisibleTime(), fast ? KB_PAN_FAST : KB_PAN_SLOW) || redraw;
      } else if (kb.isKeyDown('d') || kb.isKeyDown(SWT.ARROW_RIGHT)) {
        redraw = state.dragX(state.getVisibleTime(), -(fast ? KB_PAN_FAST : KB_PAN_SLOW)) || redraw;
      }

      if (kb.isKeyDown('q') || kb.isKeyDown(SWT.ARROW_UP)) {
        redraw = state.dragY(fast ? KB_PAN_FAST : KB_PAN_SLOW) || redraw;
      } else if (kb.isKeyDown('e') || kb.isKeyDown(SWT.ARROW_DOWN)) {
        redraw = state.dragY(-(fast ? KB_PAN_FAST : KB_PAN_SLOW)) || redraw;
      }

      if (kb.isKeyDown('w')) {
        Point mouse = canvas.toControl(getDisplay().getCursorLocation());
        redraw = rootPanel.zoom(mouse.x, 1.0 - (fast ? KB_ZOOM_FAST : KB_ZOOM_SLOW)) || redraw;
      } else if (kb.isKeyDown('s')) {
        Point mouse = canvas.toControl(getDisplay().getCursorLocation());
        redraw = rootPanel.zoom(mouse.x, 1.0 + (fast ? KB_ZOOM_FAST : KB_ZOOM_SLOW)) || redraw;
      }

      if (kb.isKeyDown('m')) {
        Selection selection = state.getSelection();
        if (selection != null) {
{'fraction_non_alphanumeric': 0.12649914334665904, 'fraction_numerical': 0.00437845040928993, 'mean_word_length': 3.6347595941773267, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 19, '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': '6076282', 'n_tokens_mistral': 3619, 'n_tokens_neox': 3490, 'n_words': 721}