private LayoutChoice_Set plot()
        {
            // sort activities by their discovery date
            // make a plot
            PlotView         plotView             = new PlotView();
            List <Datapoint> activitiesDatapoints = this.getDatapoints(this.activityDatabase.AllActivities);

            plotView.AddSeries(activitiesDatapoints, false);
            List <Datapoint> categoriesDatapoints = this.getDatapoints(this.activityDatabase.AllCategories);

            plotView.AddSeries(categoriesDatapoints, false);
            // add tick marks for years
            if (activitiesDatapoints.Count > 0)
            {
                plotView.XAxisSubdivisions = TimeProgression.AbsoluteTime.GetNaturalSubdivisions(activitiesDatapoints[0].Input, activitiesDatapoints[activitiesDatapoints.Count - 1].Input);
            }

            // add description
            string           todayText = DateTime.Now.ToString("yyyy-MM-dd");
            LayoutChoice_Set result    = new Vertical_GridLayout_Builder()
                                         .AddLayout(new TextblockLayout("Number of activities over time"))
                                         .AddLayout(new ImageLayout(plotView, LayoutScore.Get_UsedSpace_LayoutScore(1)))
                                         .AddLayout(new TextblockLayout("You have " + activitiesDatapoints.Count + " activities, " + categoriesDatapoints.Count + " of which are categories. Today is " + todayText))
                                         .BuildAnyLayout();

            return(result);
        }
        private void showErrors(PredictionErrors errors)
        {
            PlotView         plotView            = new PlotView();
            List <Datapoint> correctValues       = new List <Datapoint>();
            List <Datapoint> predictedValues     = new List <Datapoint>();
            List <Datapoint> predictedPlusStdDev = new List <Datapoint>();

            if (!double.IsInfinity(errors.MinAllowedValue))
            {
                plotView.MinY = errors.MinAllowedValue;
            }
            if (!double.IsInfinity(errors.MaxAllowedValue))
            {
                plotView.MaxY = errors.MaxAllowedValue;
            }
            DateTime referenceDate = new DateTime(2000, 1, 1);

            foreach (PredictionError error in errors.All)
            {
                double x = error.When.Subtract(referenceDate).TotalSeconds;
                correctValues.Add(new Datapoint(x, error.ActualMean, 1));
                predictedValues.Add(new Datapoint(x, error.Predicted.Mean, 1));
                predictedPlusStdDev.Add(new Datapoint(x, error.Predicted.Mean + error.Predicted.StdDev, 1));
            }
            plotView.AddSeries(correctValues, false);
            plotView.AddSeries(predictedValues, false);
            plotView.AddSeries(predictedPlusStdDev, false);

            ImageLayout     imageLayout = new ImageLayout(plotView, LayoutScore.Get_UsedSpace_LayoutScore(1));
            TextblockLayout legend      = new TextblockLayout("Prediction errors over time. Green: actual value. Blue: predicted value. White: prediction mean + stddev.");

            LayoutChoice_Set layout = new Vertical_GridLayout_Builder()
                                      .AddLayout(imageLayout)
                                      .AddLayout(legend)
                                      .BuildAnyLayout();

            this.layoutStack.AddLayout(layout, "errors");
        }
        public RelativeRatingEntryView() : base("")
        {
            this.TitleLayout.AlignVertically(TextAlignment.Center);
            this.mainDisplayGrid = GridLayout.New(new BoundProperty_List(2), new BoundProperty_List(1), LayoutScore.Zero);

            this.scaleBox              = new Editor();
            this.scaleBox.Keyboard     = Keyboard.Numeric;
            this.scaleBox.TextChanged += this.ScaleBlock_TextChanged;
            this.scaleBoxLayout        = new TextboxLayout(this.scaleBox);
            ContainerLayout scaleBoxHolder = new ContainerLayout(null, this.scaleBoxLayout, false);
            // The fact that the rating is relative to the previous participation is really important, so we put this text into its own text block.
            // Additionally, the timesBlock might be able to fit into the same line as the text box into which the user types the rating ratio.
            // Also, if there's enough space then we spell out the exact meaning more clearly
            LayoutChoice_Set conciseTimesBlock = new ScoreShifted_Layout(new TextblockLayout("x prev:").AlignVertically(TextAlignment.Center).AlignHorizontally(TextAlignment.Center), LayoutScore.Get_ReducedContent_Score(1));
            LayoutChoice_Set fullTimesBlock    = new TextblockLayout("times previous:").AlignVertically(TextAlignment.Center).AlignHorizontally(TextAlignment.Center);
            LayoutChoice_Set timesBlock        = new LayoutUnion(fullTimesBlock, conciseTimesBlock);

            LayoutChoice_Set horizontalBox = new Horizontal_GridLayout_Builder()
                                             .AddLayout(scaleBoxHolder)
                                             .AddLayout(timesBlock)
                                             .BuildAnyLayout();

            LayoutChoice_Set verticalBox = new Vertical_GridLayout_Builder()
                                           .AddLayout(scaleBoxHolder)
                                           .AddLayout(timesBlock)
                                           .BuildAnyLayout();

            this.Clear();
            this.mainDisplayGrid.AddLayout(new LayoutUnion(horizontalBox, verticalBox));

            // We try to use large font for the name layout and we also try to use as many clarifying words as possible
            this.fullNameLayout = new TextblockLayout();
            this.mainDisplayGrid.AddLayout(
                this.fullNameLayout
                );

            this.Placeholder("(Optional)");
        }
        public ParticipationEntryView(ActivityDatabase activityDatabase, LayoutStack layoutStack)
        {
            this.activityDatabase           = activityDatabase;
            activityDatabase.ActivityAdded += ActivityDatabase_ActivityAdded;
            this.layoutStack = layoutStack;

            BoundProperty_List rowHeights = new BoundProperty_List(6);

            rowHeights.BindIndices(0, 1);
            rowHeights.BindIndices(0, 2);
            rowHeights.BindIndices(0, 3);
            rowHeights.SetPropertyScale(0, 5);   // activity name and feedback
            rowHeights.SetPropertyScale(1, 5);   // rating, comments, and metrics
            rowHeights.SetPropertyScale(2, 2.3); // start and end times
            rowHeights.SetPropertyScale(3, 2);   // buttons

            // activity name and feedback
            Vertical_GridLayout_Builder nameAndFeedback_builder = new Vertical_GridLayout_Builder();

            GridLayout contents = GridLayout.New(rowHeights, BoundProperty_List.Uniform(1), LayoutScore.Zero);

            this.nameBox = new ActivityNameEntryBox("What Have You Been Doing?", activityDatabase, layoutStack);
            this.nameBox.AutoAcceptAutocomplete      = false;
            this.nameBox.PreferSuggestibleActivities = true;
            this.nameBox.NameTextChanged            += this.ActivityNameText_Changed;
            nameAndFeedback_builder.AddLayout(this.nameBox);

            this.promptHolder = new ContainerLayout();
            nameAndFeedback_builder.AddLayout(this.promptHolder);

            Button responseButton = new Button();

            responseButton.Clicked += ResponseButton_Clicked;
            this.participationFeedbackButtonLayout = new ButtonLayout(responseButton);
            contents.AddLayout(nameAndFeedback_builder.BuildAnyLayout());

            Button acceptSuggestion_button = new Button();

            acceptSuggestion_button.Clicked += AcceptSuggestions_button_Clicked;

            Button visitSuggestions_button = new Button();

            visitSuggestions_button.Clicked += VisitSuggestions_button_Clicked;
            this.suggestionLayout            = new TextblockLayout();

            this.suggestionsLayout = new Vertical_GridLayout_Builder()
                                     .AddLayout(suggestionLayout)
                                     .AddLayout(new Horizontal_GridLayout_Builder().Uniform()
                                                .AddLayout(new ButtonLayout(acceptSuggestion_button, "Yes"))
                                                .AddLayout(new ButtonLayout(visitSuggestions_button, "More ideas"))
                                                .BuildAnyLayout()
                                                )
                                     .BuildAnyLayout();

            Button experimentFeedbackButton = new Button();

            experimentFeedbackButton.Clicked += ExperimentFeedbackButton_Clicked;
            this.experimentFeedbackLayout     = new ButtonLayout(experimentFeedbackButton, "Experiment Complete!");

            Vertical_GridLayout_Builder detailsBuilder = new Vertical_GridLayout_Builder();

            GridLayout commentAndRating_grid = GridLayout.New(BoundProperty_List.Uniform(1), BoundProperty_List.Uniform(2), LayoutScore.Zero);

            this.ratingBox = new RelativeRatingEntryView();
            this.ratingBox.RatingRatioChanged += RatingBox_RatingRatioChanged;
            commentAndRating_grid.AddLayout(this.ratingBox);
            this.commentBox = new PopoutTextbox("Comment", layoutStack);
            this.commentBox.Placeholder("(Optional)");
            commentAndRating_grid.AddLayout(this.commentBox);

            detailsBuilder.AddLayout(commentAndRating_grid);
            this.todoCompletionStatusHolder = new ContainerLayout();
            this.metricChooser = new ChooseMetric_View(true);
            this.metricChooser.ChoseNewMetric += TodoCompletionLabel_ChoseNewMetric;

            LayoutChoice_Set metricLayout = new Vertical_GridLayout_Builder().Uniform()
                                            .AddLayout(this.metricChooser)
                                            .AddLayout(this.todoCompletionStatusHolder)
                                            .Build();

            this.helpStatusHolder = new ContainerLayout();
            GridLayout_Builder centered_todoInfo_builder = new Horizontal_GridLayout_Builder().Uniform();

            centered_todoInfo_builder.AddLayout(metricLayout);
            centered_todoInfo_builder.AddLayout(this.helpStatusHolder);
            GridLayout_Builder offset_todoInfo_builder = new Horizontal_GridLayout_Builder();

            offset_todoInfo_builder.AddLayout(metricLayout);
            offset_todoInfo_builder.AddLayout(this.helpStatusHolder);

            LayoutChoice_Set metricStatusLayout = new LayoutUnion(
                centered_todoInfo_builder.Build(),
                new ScoreShifted_Layout(
                    offset_todoInfo_builder.Build(),
                    LayoutScore.Get_UnCentered_LayoutScore(1)
                    )
                );

            this.helpStatusPicker = new HelpDurationInput_Layout(this.layoutStack);
            detailsBuilder.AddLayout(metricStatusLayout);
            contents.AddLayout(detailsBuilder.BuildAnyLayout());

            GridLayout grid3 = GridLayout.New(BoundProperty_List.Uniform(1), BoundProperty_List.Uniform(2), LayoutScore.Zero);

            this.startDateBox = new DateEntryView("Start Time", this.layoutStack);
            this.startDateBox.Add_TextChanged_Handler(new EventHandler <TextChangedEventArgs>(this.DateText_Changed));
            grid3.AddLayout(this.startDateBox);
            this.endDateBox = new DateEntryView("End Time", this.layoutStack);
            this.endDateBox.Add_TextChanged_Handler(new EventHandler <TextChangedEventArgs>(this.DateText_Changed));
            grid3.AddLayout(this.endDateBox);
            contents.AddLayout(grid3);
            this.setStartdateButton = new Button();
            this.setEnddateButton   = new Button();

            this.okButton = new Button();

            LayoutChoice_Set helpWindow = (new HelpWindowBuilder()).AddMessage("Use this screen to record participations.")
                                          .AddMessage("1. Type the name of the activity that you participated in, and press Enter if you want to take the autocomplete suggestion.")
                                          .AddMessage("You must have entered some activities in the activity name entry screen in order to enter them here.")
                                          .AddMessage("Notice that once you enter an activity name, ActivityRecommender will tell you how it estimates this will affect your longterm happiness.")
                                          .AddMessage("2. You may enter a rating (this is strongly recommended). The rating is a measurement of how much happiness you received per unit time from "
                                                      + "this participation divided by the amount of happiness you received per unit time for the previous. "
                                                      + "(The ratio that you enter will be combined with ActivityRecommender's previous expectations of how much you would enjoy these two "
                                                      + "participations, and will be used to create an appropriate absolute rating from 0 to 1 for this participation.)")
                                          .AddMessage("If this Activity is a ToDo, you will see a box asking you to specify whether you completed the ToDo. Press the box if you completed it.")
                                          .AddMessage("3. Enter a start date and an end date. If you use the \"End = Now\" button right when the activity completes, you don't even need to type the date in. If you " +
                                                      "do have to type the date in, press the white box.")
                                          .AddMessage("4. Enter a comment if you like.")
                                          .AddMessage("5. Lastly, press OK.")
                                          .AddMessage("It's up to you how many participations you log, how often you rate them, and how accurate the start and end dates are. ActivityRecommender will be able to " +
                                                      "provide more useful help to you if you provide more accurate data, but even just a few participations per day should still be enough for meaningful feedback.")
                                          .AddLayout(new CreditsButtonBuilder(layoutStack)
                                                     .AddContribution(ActRecContributor.AARON_SMITH, new DateTime(2019, 8, 17), "Pointed out out that it was hard to tell when the participation and suggestion screens are not yet relevant due to not having any activities")
                                                     .AddContribution(ActRecContributor.ANNI_ZHANG, new DateTime(2019, 11, 10), "Suggested disallowing entering participations having empty durations")
                                                     .AddContribution(ActRecContributor.ANNI_ZHANG, new DateTime(2019, 11, 28), "Mentioned that the keyboard was often in the way of text boxes on iOS")
                                                     .AddContribution(ActRecContributor.ANNI_ZHANG, new DateTime(2020, 1, 26), "Pointed out that feedback should be relative to average rather happiness than relative to the previous participation")
                                                     .AddContribution(ActRecContributor.ANNI_ZHANG, new DateTime(2020, 4, 19), "Discussed participation feedback messages")
                                                     .AddContribution(ActRecContributor.ANNI_ZHANG, new DateTime(2020, 7, 12), "Pointed out that the time required to log a participation can cause the end time of the next participation to be a couple minutes after the previous one")
                                                     .AddContribution(ActRecContributor.ANNI_ZHANG, new DateTime(2020, 8, 15), "Suggested that if the participation feedback recommends a different time, then it should specify which time")
                                                     .AddContribution(ActRecContributor.ANNI_ZHANG, new DateTime(2020, 8, 30), "Pointed out that participation feedback was missing more often than it should have been.")
                                                     .AddContribution(ActRecContributor.ANNI_ZHANG, new DateTime(2020, 8, 30), "Pointed out that the text in the starttime box had stopped fitting properly.")
                                                     .AddContribution(ActRecContributor.ANNI_ZHANG, new DateTime(2020, 10, 3), "Pointed out that it was possible record participations in the future.")
                                                     .AddContribution(ActRecContributor.ANNI_ZHANG, new DateTime(2021, 3, 9), "Suggested making different metrics appear more distinct.")
                                                     .AddContribution(ActRecContributor.ANNI_ZHANG, new DateTime(2021, 3, 21), "Pointed out that the participation feedback had stopped finding a better activity")
                                                     .AddContribution(ActRecContributor.ANNI_ZHANG, new DateTime(2021, 6, 6), "Suggested showing suggestions in the participation entry view")
                                                     .AddContribution(ActRecContributor.ANNI_ZHANG, new DateTime(2021, 7, 2), "Suggested shortening the text in the rating entry view")
                                                     .Build()
                                                     )
                                          .Build();

            GridLayout grid4 = GridLayout.New(BoundProperty_List.Uniform(1), BoundProperty_List.Uniform(4), LayoutScore.Zero);

            grid4.AddLayout(new ButtonLayout(this.setStartdateButton, "Start = now", 16));
            grid4.AddLayout(new ButtonLayout(this.okButton));
            grid4.AddLayout(new HelpButtonLayout(helpWindow, this.layoutStack));
            grid4.AddLayout(new ButtonLayout(this.setEnddateButton, "End = now", 16));
            contents.AddLayout(grid4);

            this.mainLayout = LayoutCache.For(contents);

            Vertical_GridLayout_Builder noActivities_help_builder = new Vertical_GridLayout_Builder();

            noActivities_help_builder.AddLayout(new TextblockLayout("This screen is where you will be able to record having participated in an activity.\n"));
            noActivities_help_builder.AddLayout(
                new HelpButtonLayout("Recording a participation is deceptively easy",
                                     new HelpWindowBuilder()
                                     .AddMessage("Autocomplete is everywhere in ActivityRecommender and is very fast. You will be impressed.")
                                     .AddMessage("Autocomplete is one of the reasons that you must enter an Activity before you can record a participation, so " +
                                                 "ActivityRecommender can know which activity you're referring to, usually after you type only one or two letters.")
                                     .Build()
                                     ,
                                     layoutStack
                                     )
                );
            noActivities_help_builder.AddLayout(
                new HelpButtonLayout("You get feedback!",
                                     new HelpWindowBuilder()
                                     .AddMessage("Nearly every time you record a participation, ActivityRecommender will give you feedback on what you're doing. " +
                                                 "This feedback will eventually contain suggestions of other things you could be doing now, and alternate times for what you " +
                                                 "did do. This feedback gets increasingly specific and increasingly accurate as you record more data, eventually including " +
                                                 "current happiness, future happiness, and future efficiency. Wow!")
                                     .Build()
                                     ,
                                     layoutStack
                                     )
                );

            noActivities_help_builder.AddLayout(new TextblockLayout("Before you can record a participation, ActivityRecommender needs you to go back " +
                                                                    "and add some activities first. Here is a convenient button for jumping directly to the Activities screen:"));

            Button activitiesButton = new Button();

            activitiesButton.Text     = "Activities";
            activitiesButton.Clicked += ActivitiesButton_Clicked;
            noActivities_help_builder.AddLayout(new ButtonLayout(activitiesButton));

            this.noActivities_explanationLayout = noActivities_help_builder.BuildAnyLayout();
        }
        public void UpdateParticipationsPlot()
        {
            DateTime start = DateTime.Now;

            if (!this.queryStartDateDisplay.IsDateValid() || !this.queryEndDateDisplay.IsDateValid())
            {
                return;
            }
            // draw the ParticipationProgression
            List <Participation> participations = this.yAxisActivity.Participations;
            DateTime             firstDate      = this.queryStartDateDisplay.GetDate();
            DateTime             lastDate       = this.queryEndDateDisplay.GetDate();
            //double firstCoordinate = this.GetXCoordinate(firstDate);
            //double lastCoordinate = this.GetXCoordinate(lastDate);
            List <Datapoint> cumulativeParticipationDurations = new List <Datapoint>();
            List <Datapoint> cumulativeEffectivenesses        = new List <Datapoint>();
            List <Datapoint> cumulativeSuggestionCounts       = new List <Datapoint>();
            List <double>    suggestionDates = new List <double>();

            PlotView newPlot = new PlotView();


            newPlot.MinX = 0;
            newPlot.MaxX = 1;

            double x1, x2, cumulativeParticipationSeconds, cumulativeEffectiveness, cumulativeSuggestionCount;

            x1 = 0;

            if (this.xAxisProgression != null)
            {
                this.configureXAxisSubdivisions(newPlot);
            }
            if (newPlot.MinX.HasValue)
            {
                x1 = newPlot.MinX.Value;
            }


            List <DateTime> startXs = new List <DateTime>(participations.Count);
            List <DateTime> endXs   = new List <DateTime>(participations.Count);

            // figure out which dates we care about
            int numActiveIntervals        = 0;
            int numIncludedParticipations = 0;

            foreach (Participation participation in participations)
            {
                // update some data about cumulative participation duration
                // make sure this participation is relevant
                if (participation.EndDate.CompareTo(firstDate) >= 0 && participation.StartDate.CompareTo(lastDate) <= 0)
                {
                    startXs.Add(this.MaxDate(firstDate, participation.StartDate));
                    endXs.Add(this.MinDate(participation.EndDate, lastDate));

                    // update some data about cumulative num suggestions
                    // this is slightly hacky - really there should be a method that just returns a list of every Suggestion for an Activity
                    if (participation.Suggested)
                    {
                        // double-check that the participation was suggested more recently than the start DateTime
                        if (participation.StartDate.CompareTo(participation.StartDate) >= 0)
                        {
                            suggestionDates.Add(this.GetXCoordinate(participation.StartDate));
                        }
                    }
                }
            }
            startXs.Sort();
            endXs.Sort();
            cumulativeParticipationSeconds = 0;
            cumulativeEffectiveness        = 0;
            DateTime prevDate = firstDate;

            while (endXs.Count > 0 || startXs.Count > 0)
            {
                DateTime participationStart;
                DateTime participationEnd;
                if (startXs.Count > 0)
                {
                    if (endXs.Count > 0)
                    {
                        participationStart = startXs[0];
                        participationEnd   = endXs[0];
                    }
                    else
                    {
                        participationStart = startXs[0];
                        participationEnd   = lastDate; // something larger that will be ignored
                    }
                }
                else
                {
                    participationEnd   = endXs[0];
                    participationStart = lastDate;      // something larger that will be ignored
                }
                if (participationStart.CompareTo(participationEnd) < 0)
                {
                    x2 = this.GetXCoordinate(participationStart);
                    double weight = x2 - x1;
                    // add datapoints denoting the start of the idle interval
                    cumulativeParticipationDurations.Add(new Datapoint(x1, cumulativeParticipationSeconds, weight));
                    cumulativeEffectivenesses.Add(new Datapoint(x1, cumulativeEffectiveness, weight));
                    // update cumulatives
                    cumulativeParticipationSeconds += weight * numActiveIntervals;
                    if (numActiveIntervals > 0)
                    {
                        Distribution efficiency = this.overallEfficiency_summarizer.GetValueDistributionForDates(prevDate, lastDate, true, false);
                        if (efficiency.Weight > 0)
                        {
                            cumulativeEffectiveness += efficiency.Mean * weight * numActiveIntervals;
                        }
                    }
                    numActiveIntervals++;
                    numIncludedParticipations++;
                    // add datapoints denoting the end of the idle interval
                    cumulativeParticipationDurations.Add(new Datapoint(x2, cumulativeParticipationSeconds, weight));
                    cumulativeEffectivenesses.Add(new Datapoint(x2, cumulativeEffectiveness, weight));
                    startXs.RemoveAt(0);
                    prevDate = participationStart;
                }
                else
                {
                    x2 = this.GetXCoordinate(participationEnd);
                    double weight = x2 - x1;
                    // add datapoints denoting the start of the active interval
                    cumulativeParticipationDurations.Add(new Datapoint(x1, cumulativeParticipationSeconds, weight));
                    cumulativeEffectivenesses.Add(new Datapoint(x1, cumulativeEffectiveness, weight));
                    cumulativeParticipationSeconds += weight * numActiveIntervals;
                    Distribution efficiency = this.overallEfficiency_summarizer.GetValueDistributionForDates(prevDate, lastDate, true, false);
                    if (efficiency.Weight > 0)
                    {
                        cumulativeEffectiveness += efficiency.Mean * weight * numActiveIntervals;
                    }
                    numActiveIntervals--;
                    // add datapoints denoting the end of the active interval
                    cumulativeParticipationDurations.Add(new Datapoint(x2, cumulativeParticipationSeconds, weight));
                    cumulativeEffectivenesses.Add(new Datapoint(x2, cumulativeEffectiveness, weight));
                    endXs.RemoveAt(0);
                    prevDate = participationEnd;
                }
                x1 = x2;
            }

            double cumulativeParticipationHours = cumulativeParticipationSeconds / 3600;
            double hoursPerTick = this.computeTickInterval(cumulativeParticipationHours);
            double spacePerTick = hoursPerTick * 3600;

            // rescale cumulativeParticipationDurations to total 1
            if (cumulativeParticipationSeconds != 0)
            {
                foreach (Datapoint item in cumulativeParticipationDurations)
                {
                    item.Output = item.Output / cumulativeParticipationSeconds;
                }
                spacePerTick = spacePerTick / cumulativeParticipationSeconds;
            }

            // rescale cumulativeEffectivenesses to total 1
            if (cumulativeEffectiveness != 0)
            {
                foreach (Datapoint item in cumulativeEffectivenesses)
                {
                    item.Output = item.Output / cumulativeEffectiveness;
                }
            }

            // We also want to plot the number of times that the activity was suggested
            cumulativeSuggestionCount = 0;
            foreach (ListItemStats <DateTime, WillingnessSummary> item in this.yAxisActivity.ConsiderationProgression.AllItems)
            {
                // make sure the participation is within the requested window
                if (item.Key.CompareTo(firstDate) >= 0 && item.Key.CompareTo(lastDate) <= 0)
                {
                    double x = this.GetXCoordinate(item.Key);
                    if (item.Value.NumSkips > 0)
                    {
                        // found a skip
                        suggestionDates.Add(x);
                    }
                }
            }
            suggestionDates.Sort();
            foreach (double x in suggestionDates)
            {
                cumulativeSuggestionCounts.Add(new Datapoint(x, cumulativeSuggestionCount, 1));
                cumulativeSuggestionCount += 1;
                cumulativeSuggestionCounts.Add(new Datapoint(x, cumulativeSuggestionCount, 1));
            }

            // rescale cumulativeSuggestionCounts to total 1
            if (cumulativeSuggestionCount != 0)
            {
                foreach (Datapoint item in cumulativeSuggestionCounts)
                {
                    item.Output /= cumulativeSuggestionCount;
                }
            }

            newPlot.AddSeries(cumulativeParticipationDurations, this.showTimeSpentTrend, this.showTimeSpent, 0);
            newPlot.AddSeries(cumulativeSuggestionCounts, false, this.showNumSuggestions, 2);
            newPlot.AddSeries(cumulativeEffectivenesses, false, this.showEffectiveness, 3);

            // assign y-axis tick marks
            if (spacePerTick > 0)
            {
                double        y      = 0;
                List <double> yTicks = new List <double>();
                while (y < 1)
                {
                    yTicks.Add(y);
                    y += spacePerTick;
                }
                newPlot.YAxisSubdivisions = yTicks;
            }

            this.participationsContent = newPlot;
            this.participationsView.SetContent(new ImageLayout(newPlot, LayoutScore.Get_UsedSpace_LayoutScore(1)));

            DateTime end = DateTime.Now;

            System.Diagnostics.Debug.WriteLine("spent " + end.Subtract(start) + " to update partipations plot");

            this.UpdateParticipationStatsView(cumulativeParticipationSeconds, numIncludedParticipations);

            // debugging
            //this.SetContent(this.participationsView.GetContent());
        }
        public void UpdateRatingsPlot()
        {
            DateTime start = DateTime.Now;

            if (!this.queryStartDateDisplay.IsDateValid() || !this.queryEndDateDisplay.IsDateValid())
            {
                return;
            }
            // draw the RatingProgression
            RatingProgression     ratingProgression = this.yAxisActivity.RatingProgression;
            List <AbsoluteRating> ratings           = ratingProgression.GetRatingsInDiscoveryOrder();
            DateTime         startDate = this.queryStartDateDisplay.GetDate();
            DateTime         endDate   = this.queryEndDateDisplay.GetDate();
            List <Datapoint> points    = new List <Datapoint>();

            // make a plot
            PlotView newPlot = new PlotView();

            newPlot.MinX = 0;
            newPlot.MaxX = endDate.Subtract(startDate).TotalDays;
            newPlot.MinY = 0;
            newPlot.MaxY = 1;

            if (this.xAxisProgression != null)
            {
                this.configureXAxisSubdivisions(newPlot);
            }

            newPlot.YAxisSubdivisions = new List <double> {
                0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1
            };

            // compute the rating at each relevant date
            foreach (AbsoluteRating rating in ratings)
            {
                if (rating.Date != null)
                {
                    double x = this.GetXCoordinate((DateTime)rating.Date);
                    // calculate y
                    double y = rating.Score;
                    // make sure we want to include it in the plot (and therefore the regression line)
                    if (x >= newPlot.MinX && x <= newPlot.MaxX)
                    {
                        points.Add(new Datapoint(x, y, 1));
                    }
                }
            }
            newPlot.AddSeries(points, this.showRatingsTrend, this.showRatings, 0);

            // compute a smoothed version of the ratings so we can show which activities are actually worth doing
            // (for example, sleeping might feel boring but might increase later happiness)
            TimeSpan totalDuration = endDate.Subtract(startDate);
            List <ScoreSummarizer> ratingSummarizers = new List <ScoreSummarizer>();

            ratingSummarizers.Add(this.overallRating_summarizer);
            ratingSummarizers.Add(this.overallEfficiency_summarizer);
            foreach (ExponentialRatingSummarizer ratingSummarizer in ratingSummarizers)
            {
                double           i;
                ScoreSummary     ratingSummary   = new ScoreSummary(endDate);
                List <Datapoint> smoothedRatings = new List <Datapoint>();
                double           maxY            = 0;
                for (i = 1; i >= 0; i -= 0.001)
                {
                    TimeSpan currentDuration = new TimeSpan((long)((double)totalDuration.Ticks * (double)i));
                    DateTime when            = startDate.Add(currentDuration);
                    if (when.CompareTo(ratingSummarizer.EarliestKnownDate) < 0)
                    {
                        break;
                    }
                    ratingSummary.Update(ratingSummarizer, when, endDate);
                    if (ratingSummary.Item.Weight > 0)
                    {
                        double x = this.GetXCoordinate(when);
                        double y = ratingSummary.Item.Mean;
                        if (!double.IsNaN(y))
                        {
                            if (ratingSummarizer == this.overallEfficiency_summarizer)
                            {
                                // rescale so that the typical value for this rating summarizer (1) is moved to match the typical value for the other plotted values (0.5)
                                y /= 2;
                            }
                            if (y > maxY)
                            {
                                maxY = y;
                            }
                            smoothedRatings.Add(new Datapoint(x, y, 1));
                        }
                    }
                }
                smoothedRatings.Reverse();
                // if the plot overflowed, rescale it to fit
                if (maxY > 1)
                {
                    foreach (Datapoint datapoint in smoothedRatings)
                    {
                        datapoint.Output = datapoint.Output / maxY;
                    }
                }
                if (ratingSummarizer == this.overallRating_summarizer)
                {
                    newPlot.AddSeries(smoothedRatings, false, this.showOverallHappiness, 2);
                }
                else
                {
                    newPlot.AddSeries(smoothedRatings, this.showEfficiencyTrend, this.showEfficiency, 3);
                }
            }

            DateTime end = DateTime.Now;

            this.ratingsView.SetContent(new ImageLayout(newPlot, LayoutScore.Get_UsedSpace_LayoutScore(1)));

            System.Diagnostics.Debug.WriteLine("spent " + end.Subtract(start) + " to update ratings plot");
        }
Exemplo n.º 7
0
        public Full_RequestSuggestion_Layout(ActivityDatabase activityDatabase, bool allowRequestingActivitiesDirectly, bool allowMultipleSuggestionTypes, bool vertical,
                                             int numChoicesPerSuggestion, Engine engine, LayoutStack layoutStack)
        {
            this.numChoicesPerSuggestion = numChoicesPerSuggestion;
            Button suggestionButton = new Button();

            suggestionButton.Clicked += SuggestBestActivity_Clicked;
            ButtonLayout suggest_maxLongtermHappiness_button;

            if (allowMultipleSuggestionTypes)
            {
                suggest_maxLongtermHappiness_button = new ButtonLayout(suggestionButton, "Best");
            }
            else
            {
                suggest_maxLongtermHappiness_button = new ButtonLayout(suggestionButton, "Suggest");
            }
            LayoutChoice_Set suggestButton_layout;

            if (allowRequestingActivitiesDirectly)
            {
                GridLayout_Builder builder = new Vertical_GridLayout_Builder().Uniform().AddLayout(suggest_maxLongtermHappiness_button);
                if (allowMultipleSuggestionTypes)
                {
                    Button suggestionButton2 = new Button();
                    suggestionButton2.Clicked += SuggestMostLikelyActivity_Clicked;
                    ButtonLayout suggest_mostLikely_button = new ButtonLayout(suggestionButton2, "Most Likely");
                    builder.AddLayout(suggest_mostLikely_button);

                    Button suggestionButton3 = new Button();
                    suggestionButton3.Clicked += SuggestMostEfficientActivity_Clicked;
                    ButtonLayout suggest_mostEfficient_button = new ButtonLayout(suggestionButton3, "Most Future Efficiency");
                    builder.AddLayout(suggest_mostEfficient_button);
                }
                suggestButton_layout = builder.BuildAnyLayout();
            }
            else
            {
                suggestButton_layout = suggest_maxLongtermHappiness_button;
            }

            this.categoryBox = new ActivityNameEntryBox("Category:", activityDatabase, layoutStack);
            this.categoryBox.Placeholder("(Optional)");
            this.activityDatabase = activityDatabase;
            this.engine           = engine;
            this.layoutStack      = layoutStack;


            if (!allowRequestingActivitiesDirectly)
            {
                this.SubLayout = suggest_maxLongtermHappiness_button;
            }
            else
            {
                GridLayout configurationLayout = GridLayout.New(BoundProperty_List.Uniform(2), new BoundProperty_List(1), LayoutScore.Zero);
                configurationLayout.AddLayout(this.categoryBox);


                this.atLeastAsFunAs_button     = new Button();
                atLeastAsFunAs_button.Clicked += RequestAsFunAs_Button_Clicked;
                configurationLayout.AddLayout(new TitledControl("As fun as:", new ButtonLayout(atLeastAsFunAs_button)));

                if (vertical)
                {
                    GridLayout verticalContentLayout = GridLayout.New(new BoundProperty_List(2), new BoundProperty_List(1), LayoutScore.Get_UnCentered_LayoutScore(2));
                    verticalContentLayout.AddLayout(configurationLayout);
                    verticalContentLayout.AddLayout(suggestButton_layout);
                    this.SubLayout = verticalContentLayout;
                }
                else
                {
                    GridLayout horizontalContentLayout = GridLayout.New(new BoundProperty_List(1), new BoundProperty_List(2), LayoutScore.Get_UnCentered_LayoutScore(1));
                    horizontalContentLayout.AddLayout(suggestButton_layout);
                    horizontalContentLayout.AddLayout(configurationLayout);

                    this.SubLayout = horizontalContentLayout;
                }
                this.specify_AtLeastAsFunAs_Layout = new Specify_AtLeastAsFunAs_Layout(this.activityDatabase, this.layoutStack);
                this.update_atLeastAsFunAs_activity();
            }
        }
Exemplo n.º 8
0
        private void UpdateLayout_From_Suggestions()
        {
            List <LayoutChoice_Set> layouts = new List <LayoutChoice_Set>();

            // show feedback if there is any
            if (this.messageLayout.ModelledText != "")
            {
                layouts.Add(messageLayout);
            }
            // show suggestions if there are any
            bool addDoNowButton = true;

            if (this.suggestions.Count > 0)
            {
                foreach (ActivitiesSuggestion suggestion in this.suggestions)
                {
                    Dictionary <ActivitySuggestion, bool> repeatingDeclinedSuggestion = new Dictionary <ActivitySuggestion, bool>();
                    foreach (ActivitySuggestion child in suggestion.Children)
                    {
                        if (this.previousDeclinedSuggestion != null && this.previousDeclinedSuggestion.CanMatch(child.ActivityDescriptor))
                        {
                            repeatingDeclinedSuggestion[child] = true;
                        }
                        else
                        {
                            repeatingDeclinedSuggestion[child] = false;
                        }
                    }
                    layouts.Add(this.makeLayout(suggestion, addDoNowButton, repeatingDeclinedSuggestion));
                    addDoNowButton = false;
                }
            }
            // Show an explanation about how multiple suggestions work (they're in chronological order) if there's room
            // Also be sure to save room for the suggestion buttons
            if (layouts.Count <= this.maxNumSuggestions - 2)
            {
                if (this.suggestions.Count > 0)
                {
                    this.askWhatIsNext_layout.setText("What's after that?");
                    layouts.Add(this.askWhatIsNext_layout);
                }
            }

            // show the button for getting more suggestions if there's room
            if (this.suggestions.Count < this.maxNumSuggestions)
            {
                layouts.Add(this.requestSuggestion_layout);
            }
            // show help and experiments if there are no suggestions visible
            if (this.suggestions.Count < 1)
            {
                layouts.Add(this.bottomLayout);
            }

            LayoutChoice_Set even   = new Vertical_GridLayout_Builder().Uniform().AddLayouts(layouts).BuildAnyLayout();
            LayoutChoice_Set uneven = new ScoreShifted_Layout(new Vertical_GridLayout_Builder().AddLayouts(layouts).BuildAnyLayout(), LayoutScore.Get_UnCentered_LayoutScore(1));

            this.SetContent(new LayoutUnion(even, uneven));
        }
        public ExperimentDifficultyEstimateLayout(SuggestedMetric suggestedMetric, Activity activity)
        {
            this.suggestedMetric = suggestedMetric;

            this.metricChooser = new ChooseMetric_View(false);
            this.metricChooser.SetActivity(activity);
            this.metricChooser.Choose(suggestedMetric.PlannedMetric.MetricName);

            this.difficultyBox              = new Editor();
            this.difficultyBox.Keyboard     = Keyboard.Numeric;
            this.difficultyBox.Placeholder  = this.defaultDifficulty.ToString();
            this.difficultyLayout           = new TitledControl("Difficulty:", new TextboxLayout(difficultyBox));
            this.difficultyBox.TextChanged += DifficultyBox_TextChanged;

            TextblockLayout nameLayout = new TextblockLayout(activity.Name);

            GridLayout evenGrid   = GridLayout.New(new BoundProperty_List(1), BoundProperty_List.Uniform(3), LayoutScore.Zero);
            GridLayout unevenGrid = GridLayout.New(new BoundProperty_List(1), new BoundProperty_List(3), LayoutScore.Get_UnCentered_LayoutScore(1));

            evenGrid.AddLayout(this.metricChooser);
            unevenGrid.AddLayout(this.metricChooser);

            evenGrid.AddLayout(nameLayout);
            unevenGrid.AddLayout(nameLayout);

            evenGrid.AddLayout(this.difficultyLayout);
            unevenGrid.AddLayout(this.difficultyLayout);


            this.SubLayout = new LayoutUnion(evenGrid, unevenGrid);
        }
Exemplo n.º 10
0
        public ActivityNameEntryBox(string title, ActivityDatabase activityDatabase, LayoutStack layoutStack, bool createNewActivity = false, bool placeTitleAbove = true)
        {
            // some settings
            this.layoutStack               = layoutStack;
            this.AutoAcceptAutocomplete    = true;
            this.createNewActivity         = createNewActivity;
            this.activityDatabase          = activityDatabase;
            this.numAutocompleteRowsToShow = 1;

            // the box the user is typing in
            this.nameBox              = new Editor();
            this.nameBox.TextChanged += NameBox_TextChanged;
            this.nameBox_layout       = new TextboxLayout(this.nameBox);

            // "X"/"?" button for clearing text or getting help
            // We use one button for both purposes so that the layout doesn't relayout (and shift focus) when this button switches from one to the other
            this.sideButton          = new Button();
            this.sideButton.Clicked += SideButton_Clicked;
            this.sideButtonLayout    = new ButtonLayout(this.sideButton);

            // layouts controlling the alignment of the main text box and the side button
            this.sideLayout           = new ContainerLayout();
            this.sideLayout.SubLayout = this.sideButtonLayout;

            GridView   gridView = new GridView();
            GridLayout evenBox  = GridLayout.New(new BoundProperty_List(1), BoundProperty_List.WithRatios(new List <double>()
            {
                7, 1
            }), LayoutScore.Zero, 1, gridView);
            GridLayout unevenBox = GridLayout.New(new BoundProperty_List(1), new BoundProperty_List(2), LayoutScore.Get_UnCentered_LayoutScore(1), 1, gridView);

            evenBox.AddLayout(this.nameBox_layout);
            evenBox.AddLayout(this.sideLayout);
            unevenBox.AddLayout(this.nameBox_layout);
            unevenBox.AddLayout(this.sideLayout);
            this.nameBoxWithSideLayout = new LayoutUnion(evenBox, unevenBox);

            // the autocomplete above the text box
            this.autocompleteLayout = new TextblockLayout();
            this.autocompleteLayout.ScoreIfEmpty = false;

            // button that gives help with autocomplete
            this.helpWindow = new HelpWindowBuilder()
                              .AddMessage("This screen explains how to enter " + title + " in the previous screen. " +
                                          "If you haven't already created the activity that you want to enter here, you will have to go back and create it first in the Activities screen.")
                              .AddMessage("")
                              .AddMessage("To input an activity name, you may type it in using the letters on the keyboard.")
                              .AddMessage("While you do this, ActivityRecommender will try to guess which activity you mean, and " +
                                          "that autocomplete guess will appear above. If this autocomplete suggestion is what you want, then you can press " +
                                          "[enter] to use the autocomplete suggestion.")
                              .AddMessage("Autocomplete does not require you to type full words but it does require spaces between words.")
                              .AddMessage("Autocomplete does not require that you type letters using the correct case but it is more effective if you do.")
                              .AddMessage("Consider the following example:")
                              .AddMessage("If you have already entered an activity named \"Taking out the Garbage\", " +
                                          "here are some things you can type that might cause it to become the autocomplete suggestion:")
                              .AddMessage("Taking out the")
                              .AddMessage("Taking")
                              .AddMessage("out")
                              .AddMessage("Garbage")
                              .AddMessage("garbage")
                              .AddMessage("Taking o t G")
                              .AddMessage("T o t G")
                              .AddMessage("T")
                              .AddMessage("G")
                              .AddMessage("t")
                              .AddMessage("")
                              .AddMessage("Note, of course, that the longer and more unique your text, the more likely that it will be matched with the activity that you intend, rather than " +
                                          "with another activity, like for example, 'Talking on the Phone'")
                              .AddLayout(new CreditsButtonBuilder(layoutStack)
                                         .AddContribution(ActRecContributor.ANNI_ZHANG, new DateTime(2020, 6, 7), "Pointed out that completed ToDos should have a very low autocomplete priority")
                                         .Build()
                                         )
                              .Build();

            // help buttons that appear when the user types something invalid
            Button help_createNew_button = new Button();

            help_createNew_button.Clicked   += help_createNew_button_Clicked;
            this.autocomplete_longHelpLayout = new Horizontal_GridLayout_Builder().Uniform()
                                               .AddLayout(new ButtonLayout(help_createNew_button, "Create"))
                                               .AddLayout(new HelpButtonLayout(this.helpWindow, layoutStack))
                                               .Build();

            // the main layout that contains everything
            LayoutChoice_Set content;

            if (createNewActivity)
            {
                content = unevenBox;
            }
            else
            {
                GridLayout contentWithFeedback = GridLayout.New(new BoundProperty_List(2), new BoundProperty_List(1), LayoutScore.Get_UnCentered_LayoutScore(1));
                contentWithFeedback.AddLayout(this.responseLayout);
                contentWithFeedback.AddLayout(this.nameBoxWithSideLayout);

                content = contentWithFeedback;

                this.UpdateFeedback();
            }

            this.updateSideButton();

            TextblockLayout titleLayout = new TextblockLayout(title);

            titleLayout.AlignHorizontally(TextAlignment.Center);
            if (placeTitleAbove)
            {
                this.SubLayout = new Vertical_GridLayout_Builder()
                                 .AddLayout(titleLayout)
                                 .AddLayout(content)
                                 .Build();
            }
            else
            {
                GridLayout evenGrid   = GridLayout.New(new BoundProperty_List(1), BoundProperty_List.Uniform(2), LayoutScore.Zero);
                GridLayout unevenGrid = GridLayout.New(new BoundProperty_List(1), new BoundProperty_List(2), LayoutScore.Get_UnCentered_LayoutScore(1));
                evenGrid.AddLayout(titleLayout);
                unevenGrid.AddLayout(titleLayout);
                evenGrid.AddLayout(content);
                unevenGrid.AddLayout(content);
                this.SubLayout = new LayoutUnion(evenGrid, unevenGrid);
            }
        }