mirror of
https://github.com/joeycastillo/second-movement.git
synced 2026-02-05 01:15:26 +00:00
update 'new watch face' script
This commit is contained in:
97
template/template.c
Normal file
97
template/template.c
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) <#year#> <#author_name#>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation 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 PARTICULAR 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 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "<#watch_face_name#>_face.h"
|
||||
|
||||
void <#watch_face_name#>_face_setup(uint8_t watch_face_index, void ** context_ptr) {
|
||||
(void) watch_face_index;
|
||||
if (*context_ptr == NULL) {
|
||||
*context_ptr = malloc(sizeof(<#watch_face_name#>_state_t));
|
||||
memset(*context_ptr, 0, sizeof(<#watch_face_name#>_state_t));
|
||||
// Do any one-time tasks in here; the inside of this conditional happens only at boot.
|
||||
}
|
||||
// Do any pin or peripheral setup here; this will be called whenever the watch wakes from deep sleep.
|
||||
}
|
||||
|
||||
void <#watch_face_name#>_face_activate(void *context) {
|
||||
<#watch_face_name#>_state_t *state = (<#watch_face_name#>_state_t *)context;
|
||||
|
||||
// Handle any tasks related to your watch face coming on screen.
|
||||
}
|
||||
|
||||
bool <#watch_face_name#>_face_loop(movement_event_t event, void *context) {
|
||||
<#watch_face_name#>_state_t *state = (<#watch_face_name#>_state_t *)context;
|
||||
|
||||
switch (event.event_type) {
|
||||
case EVENT_ACTIVATE:
|
||||
// Show your initial UI here.
|
||||
break;
|
||||
case EVENT_TICK:
|
||||
// If needed, update your display here.
|
||||
break;
|
||||
case EVENT_LIGHT_BUTTON_UP:
|
||||
// You can use the Light button for your own purposes. Note that by default, Movement will also
|
||||
// illuminate the LED in response to EVENT_LIGHT_BUTTON_DOWN; to suppress that behavior, add an
|
||||
// empty case for EVENT_LIGHT_BUTTON_DOWN.
|
||||
break;
|
||||
case EVENT_ALARM_BUTTON_UP:
|
||||
// Just in case you have need for another button.
|
||||
break;
|
||||
case EVENT_TIMEOUT:
|
||||
// Your watch face will receive this event after a period of inactivity. If it makes sense to resign,
|
||||
// you may uncomment this line to move back to the first watch face in the list:
|
||||
// movement_move_to_face(0);
|
||||
break;
|
||||
case EVENT_LOW_ENERGY_UPDATE:
|
||||
// If you did not resign in EVENT_TIMEOUT, you can use this event to update the display once a minute.
|
||||
// Avoid displaying fast-updating values like seconds, since the display won't update again for 60 seconds.
|
||||
// You should also consider starting the tick animation, to show the wearer that this is sleep mode:
|
||||
// watch_start_sleep_animation(500);
|
||||
break;
|
||||
default:
|
||||
// Movement's default loop handler will step in for any cases you don't handle above:
|
||||
// * EVENT_LIGHT_BUTTON_DOWN lights the LED
|
||||
// * EVENT_MODE_BUTTON_UP moves to the next watch face in the list
|
||||
// * EVENT_MODE_LONG_PRESS returns to the first watch face (or skips to the secondary watch face, if configured)
|
||||
// You can override any of these behaviors by adding a case for these events to this switch statement.
|
||||
return movement_default_loop_handler(event);
|
||||
}
|
||||
|
||||
// return true if the watch can enter standby mode. Generally speaking, you should always return true.
|
||||
// Exceptions:
|
||||
// * If you are displaying a color using the low-level watch_set_led_color function, you should return false.
|
||||
// * If you are sounding the buzzer using the low-level watch_set_buzzer_on function, you should return false.
|
||||
// Note that if you are driving the LED or buzzer using Movement functions like movement_illuminate_led or
|
||||
// movement_play_alarm, you can still return true. This guidance only applies to the low-level watch_ functions.
|
||||
return true;
|
||||
}
|
||||
|
||||
void <#watch_face_name#>_face_resign(void *context) {
|
||||
(void) context;
|
||||
|
||||
// handle any cleanup before your watch face goes off-screen.
|
||||
}
|
||||
|
||||
52
template/template.h
Normal file
52
template/template.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) <#year#> <#author_name#>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation 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 PARTICULAR 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 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "movement.h"
|
||||
|
||||
/*
|
||||
* A DESCRIPTION OF YOUR WATCH FACE
|
||||
*
|
||||
* and a description of how use it
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
// Anything you need to keep track of, put it here!
|
||||
uint8_t unused;
|
||||
} <#watch_face_name#>_state_t;
|
||||
|
||||
void <#watch_face_name#>_face_setup(uint8_t watch_face_index, void ** context_ptr);
|
||||
void <#watch_face_name#>_face_activate(void *context);
|
||||
bool <#watch_face_name#>_face_loop(movement_event_t event, void *context);
|
||||
void <#watch_face_name#>_face_resign(void *context);
|
||||
|
||||
#define <#watch_face_name#>_face ((const watch_face_t){ \
|
||||
<#watch_face_name#>_face_setup, \
|
||||
<#watch_face_name#>_face_activate, \
|
||||
<#watch_face_name#>_face_loop, \
|
||||
<#watch_face_name#>_face_resign, \
|
||||
NULL, \
|
||||
})
|
||||
102
template/watch_face.py
Normal file
102
template/watch_face.py
Normal file
@ -0,0 +1,102 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2022 David Keck
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation 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 PARTICULAR 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 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import datetime
|
||||
import argparse
|
||||
|
||||
|
||||
MAKEFILE_INDICATOR = "# New watch faces go above this line.\n"
|
||||
INCLUDE_INDICATOR = "// New includes go above this line.\n"
|
||||
|
||||
|
||||
def replace_placeholders(contents, args):
|
||||
modified_contents = contents.replace("<#WATCH_FACE_NAME#>", args.watch_face_name.upper())
|
||||
modified_contents = modified_contents.replace("<#watch_face_name#>", args.watch_face_name)
|
||||
modified_contents = modified_contents.replace("<#year#>", datetime.datetime.now().strftime("%Y"))
|
||||
if args.author_name:
|
||||
modified_contents = modified_contents.replace("<#author_name#>", " ".join(args.author_name))
|
||||
|
||||
return modified_contents
|
||||
|
||||
|
||||
def write_modified_template(args, file_type, output_dir):
|
||||
with open(f"template.{file_type}", 'r') as file_template:
|
||||
file_contents = file_template.read()
|
||||
modified_template = replace_placeholders(file_contents, args)
|
||||
file_path = f"{output_dir}{args.watch_face_name}_face.{file_type}"
|
||||
if not os.path.exists(file_path):
|
||||
with open(file_path, 'w') as output_file:
|
||||
output_file.write(modified_template)
|
||||
print(f"Created {file_path}.")
|
||||
else:
|
||||
print(f"Generation failed: the watch face \"{args.watch_face_name}\" already exists at {file_path}. Unable to generate new files. Exiting...")
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def update_include_file(file_path, indicator_line, line_to_insert):
|
||||
with open(file_path, 'r+') as include_file:
|
||||
include_contents = include_file.readlines()
|
||||
if line_to_insert not in include_contents:
|
||||
new_face_index = include_contents.index(indicator_line)
|
||||
include_contents.insert(new_face_index, line_to_insert)
|
||||
include_file.seek(0)
|
||||
include_file.writelines(include_contents)
|
||||
print(f"Updated {file_path}.")
|
||||
else:
|
||||
print(f"Generation failed: {file_path} already has an entry for {line_to_insert.strip()}. Unable to generate new files. Exiting...")
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Create a new watch face.")
|
||||
parser.add_argument("watch_face_type", metavar="face_type", type=str, choices=["clock", "complication", "demo", "sensor", "settings"], help="The type of watch face to create ('clock', 'complication', 'demo', 'sensor', 'settings')")
|
||||
parser.add_argument("watch_face_name", metavar="face_name", type=str, help="The name of the watch face. Use underscores between words if you have more than one.")
|
||||
parser.add_argument("--author-name", metavar="author_name", type=str, nargs='*', help="The name of the author")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
name_valid = re.fullmatch(r'[a-zA-Z_][a-zA-Z0-9_]*', args.watch_face_name)
|
||||
if name_valid is None:
|
||||
print(f"Generation failed: {args.watch_face_name} is not a valid C variable name. Exiting...")
|
||||
sys.exit(0)
|
||||
|
||||
if not args.author_name:
|
||||
print("Note: the \"--author-name\" argument was not supplied via command line. \"<#author_name#>\" will not be replaced in generated template.")
|
||||
|
||||
line_to_insert = f"#include \"{args.watch_face_name}_face.h\"\n"
|
||||
update_include_file(f"..{os.sep}movement_faces.h", INCLUDE_INDICATOR, line_to_insert)
|
||||
|
||||
line_to_insert = f" .{os.sep}watch-faces{os.sep}{args.watch_face_type}{os.sep}{args.watch_face_name}_face.c \\\n"
|
||||
update_include_file(f"..{os.sep}watch-faces.mk", MAKEFILE_INDICATOR, line_to_insert)
|
||||
|
||||
output_dir = f"..{os.sep}watch-faces{os.sep}{args.watch_face_type}{os.sep}"
|
||||
write_modified_template(args, "h", output_dir)
|
||||
write_modified_template(args, "c", output_dir)
|
||||
|
||||
print(f"Successfully generated the {args.watch_face_name} {args.watch_face_type} and updated include files.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user