Skip to content

Commit

Permalink
git subrepo pull programs/jspaint
Browse files Browse the repository at this point in the history
subrepo:
  subdir:   "programs/jspaint"
  merged:   "f7fea8b1"
upstream:
  origin:   "https://github.com/1j01/jspaint.git"
  branch:   "master"
  commit:   "f7fea8b1"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"
  • Loading branch information
1j01 committed Aug 6, 2021
1 parent ef36738 commit b24eeee
Show file tree
Hide file tree
Showing 2,101 changed files with 40,010 additions and 2,552 deletions.
2 changes: 1 addition & 1 deletion programs/jspaint/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ module.exports = {
"memoize_synchronous_function": "writable",
"invert_rgb": "off",
"get_theme": "writable",
"get_tool_by_name": "writable",
"get_tool_by_id": "writable",
"redo": "writable",
"undo": "writable",
"undoable": "writable",
Expand Down
4 changes: 2 additions & 2 deletions programs/jspaint/.gitrepo
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/1j01/jspaint.git
branch = master
commit = 8a0f27172d29802fb97fd9e031c872166d8a89cc
parent = 01dbdbc80ff353d27b0ad171dacec0056e7c7bba
commit = f7fea8b12d7900d4aaffab3a5875849cb499dbf6
parent = ef36738f4fe4fdae9489f911b7bf0e377e4bf0b6
method = merge
cmdver = 0.4.3
5 changes: 4 additions & 1 deletion programs/jspaint/.travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,8 @@ cache:
- ~/.cache
install:
- npm ci
before_script:
- npm run test:start-server &
- sleep 3 # hopefully the server will be listening by then
script:
- npm run lint && npm run test
- npm run lint && npm run cy:run
48 changes: 27 additions & 21 deletions programs/jspaint/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,44 @@
# Contributing

#### Pull Requests
## Pull Requests

Let me know before you work on something by opening an issue or commenting on an existing one.
I don't want your effort to be wasted!

#### Issues

Open issues! Search for issues first, but open issues for features, issues for problems...
Someone may be already working on it, or I may have specific plans or requirements.
I don't want your effort to be wasted!

Feel free to open issues in a "meta" context, like "hey, maybe you should tag issues with 'good first issue'" etc.
## Issues

https://github.com/1j01/jspaint/issues
[Bugs and feature requests are tracked on GitHub.](https://github.com/1j01/jspaint/issues)

You can also just [email me](mailto:[email protected]) if you prefer (and I'll probably create an issue).
Before opening an issue for a bug or feature request, search to see if it's already been reported.

#### Windows 98
You can also [email me](mailto:[email protected]) if you prefer.

JS Paint's GUI is primarily based on Paint from Windows 98.
There's a nice [online emulator here](https://copy.sh/v86/?profile=windows98)
that you can play around with and/or use as a reference.
## Windows 98

You can open issues relating to that UI, but also for general functionality that isn't necessarily in mspaint,
for instance jspaint already has affordances like unlimited undos, extra menu items, and shortcut-like features.
Note: JS Paint's GUI is primarily based on Paint from Windows 98.
There's a nice [online emulator](https://copy.sh/v86/?profile=windows98)
that you can play around with and use as a reference.

## Dev Setup

* Install Node.js if you don't have it (and maybe update it)
* Clone the repo
* Install dependencies with `npm i`
* Run `npm run dev` to start up a live-reloading web server
See [**Development Setup**](./README.md#Development-Setup) on the readme.

### Project Structure

It's messy. A lot of stuff is in a file simply called "functions.js", to give you an idea of it.

I can go into more detail [if you want..](https://github.com/1j01/jspaint/issues)
- `index.html` and `app.js` are the main entry points for the app.
- `functions.js` has functions that shouldn't own any global state, altho they very much modify global state, and there may be a few stateful global variables defined in there.
- The project uses [jQuery](https://jquery.com/), and a convention of prefixing variables that hold jQuery objects with `$`
- There are also some weird pseudo-classes like `$ColorBox` which extend and return jQuery objects. I don't recommend this pattern for new code.
- Menu code and some windowing code is in `lib/os-gui/` and should be kept in sync with the [os-gui](https://github.com/1j01/os-gui) project.
- Some other windowing code is in $ToolWindow.js, for windows that don't have maximize/minimize buttons; eventually this should be provided by os-gui.
- `image-manipulation.js` should contain just rendering related code, and ideally no dialogs except maybe some error messages.
- Some image manipulation code is also in `tools.js` and `functions.js`
- CSS is in `styles/`
- Layout-important CSS is kept separate from theme CSS
- Localization data is in `localization/`
- As of writing there's no good way to contribute translations, but [get in touch!](https://github.com/1j01/jspaint/issues/80)

Any good IDE or code editor has a project-wide search (often with <kbd>Ctrl+Shift+F</kbd>). I use this all the time.
I also use the "Intellisense" feature of [VS Code](https://code.visualstudio.com/) to jump to function definitions (an extra convenience over searching for function names).
47 changes: 24 additions & 23 deletions programs/jspaint/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@

A nice web-based MS Paint remake and more... [Try it out!](https://jspaint.app)

<!-- TODO: You can also run it as a [desktop app...](#desktop-app) -->


The goal is to remake MS Paint
(including its [little-known features](#did-you-know)),
improve on it, and to extend the types of images it can edit.
Expand Down Expand Up @@ -40,31 +37,36 @@ I want to bring good old paint into the modern era.
* Cross-platform
* Unlimited undos/redos (as opposed to a measly 3 in Windows XP,
or a measly 50 in Windows 7)
* Undo history is *nonlinear*, which means if you undo and do something other than redo, the redos aren't destroyed. Instead, a new branch in the history tree is created. Jump to any point in history with <kbd>Ctrl+Shift+Y</kbd>
* Undo history is *nonlinear*, which means if you undo and do something other than redo, the redos aren't discarded. Instead, a new branch is created in the *history tree*. Jump to any point in history with **Edit > History** or <kbd>Ctrl+Shift+Y</kbd>
* Automatically keeps a backup of your image. Only one backup per image tho, which doesn't give you a lot of safety. Remember to save with **File > Save** or <kbd>Ctrl+S</kbd>! Manage backups with **File > Manage Storage**.
* Edit transparent images! To create a transparent image,
go to **Image > Attributes...** and select Transparent,
then Okay, and then **Image > Clear Image** or use the Eraser tool.
then OK, and then **Image > Clear Image** or use the Eraser tool.
Images with *any* translucent pixels will open in Transparent mode.
* Switch themes from the Extras menu
* Switch themes from the Extras menu. Dark mode included.
* [Vertical Color Box mode](https://jspaint.app/#vertical-color-box-mode), accessible from **Extras > Vertical Color Box**
* [Eye Gaze Mode](https://jspaint.app/#eye-gaze-mode), for use with an eye tracker, head tracker, or other coarse input device, accessible from **Extras > Eye Gaze Mode**. (With just a webcam, you can try it out with [Enable Viacam](https://eviacam.crea-si.com/) (head tracker) or [GazePointer](https://sourceforge.net/projects/gazepointer/) (eye tracker).)
* [Speech Recognition Mode](https://jspaint.app/#speech-recognition-mode).
Using your voice you can select tools and colors, pan the view ("scroll down and to the left", or "go southwest", etc.), explore the menus (but you can activate any menu item without opening the menus first), interact with windows (including scrolling the history view with "scroll up"/"scroll down" etc.), dictate text with the Text tool, and even tell the application to sketch things (for instance, "draw a house")
* Create an animated GIF from the current document history.
Accessible from the Extras menu or with <kbd>Ctrl+Shift+G</kbd>.
It's pretty nifty, you should try it out!
You might want to limit the size of the image though.
* You can shoot at it [Asteroids style](https://kickassapp.com/)
* You can shoot at the application [Asteroids style](https://kickassapp.com/)
* When you do **Edit > Paste From...** you can select transparent images.
~~You can even paste a transparent animated GIF and then
hold <kbd>Shift</kbd> while dragging the selection to
smear it across the canvas *while it animates*!~~
Update: This was [due to not-to-spec behavior in Chrome.](https://christianheilmann.com/2014/04/16/browser-inconsistencies-animated-gif-and-drawimage/)
I may reimplement this in the future as I really liked this feature.
* You can open SVG files, though only as a bitmap.
(And you can't choose a size for the bitmap when opening an SVG. It may open super large, or tiny.)
(Note: it may open super large, or tiny. There's no option to choose a size when opening.)
* You can crop the image by making a selection while holding <kbd>Ctrl</kbd>
* Keyboard shortcuts for rotation: <kbd>Ctrl+.</kbd> and <kbd>Ctrl+,</kbd> (<kbd><</kbd> and <kbd>></kbd>)
* Rotate by any arbitrary angle in **Image > Flip/Rotate**
* In **Image > Stretch/Skew**, you can stretch more than 500% at once
* Zoom to an arbitrary scale in **View > Zoom > Custom...**
* Zoom to fit the canvas within the window with **View > Zoom > Zoom To Window**
* Non-contiguous fill: Replace a color in the entire image by holding <kbd>Shift</kbd> when using the fill tool
* You can use the Text tool at any zoom level, and it previews the exact pixels that will end up on the canvas.
* Spellcheck is available in the textbox if your browser supports it.
Expand All @@ -77,7 +79,7 @@ I want to bring good old paint into the modern era.
If you want better collaboration support, follow the development of [Mopaint](https://github.com/1j01/mopaint).
* Load many different palette formats with **Colors > Get Colors**.
(I made a [library](https://github.com/1j01/palette.js/) for this.)
* Mobile support (altho fairly lacking in some areas). Use two fingers to pan the view.
* Touch support: use two fingers to pan the view.
* Click/tap the selected colors area to swap the foreground and background colors

![JS Paint drawing of JS Paint on a phone](images/meta/mobipaint.png)
Expand All @@ -94,8 +96,6 @@ In other browsers you can still can copy with <kbd>Ctrl+C</kbd>, cut with <kbd>C
but data copied from JS Paint can only be pasted into other instances of JS Paint.
External images can be pasted in.

(There's also a partially-built [desktop app](#desktop-app) version you can install that has full clipboard support, and also lets you set the wallpaper.)


## Did you know?

Expand Down Expand Up @@ -131,14 +131,9 @@ External images can be pasted in.

## Desktop App

I've started work on a desktop app, built with [Electron][] and [Electron Forge][].
JS Paint can be installed as a PWA, altho it doesn't work offline.

There are no releases yet, but much of the groundwork has been laid, and several features implemented.

Why did I do this.
I hate electron apps. They're so slow and bulky...

If you're interested, comment on [this issue](https://github.com/1j01/jspaint/issues/2).
(Also I made some effort to build it into a desktop app with [Electron][] and [Electron Forge][], but this will use unnecessary system resources and is not recommended. See [this issue](https://github.com/1j01/jspaint/issues/2).)

[Electron]: https://electronjs.org/
[Electron Forge]: https://electronforge.io/
Expand Down Expand Up @@ -166,19 +161,25 @@ Tests are also run in continuous integration [with Travis CI](https://travis-ci.

### Web App (https://jspaint.app)

You just need an HTTP server, but [Live Server][] is recommended. It auto reloads when you save changes.
After you've installed dependencies with `npm i`,
use `npm run dev` to start a live-reloading server.

It's included in `package.json` so if you've installed dependencies (`npm i`) you can use `npm run dev` to run it.
(It's configured to ignore some files/directories for reloading.)
Make sure any layout-important styles go in `layout.css`.
When updating `layout.css`, a right-to-left version of the stylesheet is generated, using [RTLCSS](https://rtlcss.com/).
You should test the RTL layout by changing the language to Arabic or Hebrew.
Go to **Extras > Language > العربية** or **עברית**.
See [Control Directives](https://rtlcss.com/learn/usage-guide/control-directives/) for how to control the RTL layout.

### Desktop App (Electron)

This is unreleased and not in development.

- Install dependencies with `npm i`
- Start the electron app with `npm start`
- Start the electron app with `npm run electron:start`

[electron-debug][] and [devtron][] are included, so you can use <kbd>Ctrl+R</kbd> to reload and <kbd>F12</kbd>/<kbd>Ctrl+Shift+I</kbd> to open the devtools, and there's a Devtron tab with tools specific to Electron.

You can build for production with `npm run make`
You can build for production with `npm run electron:make`

[Live Server]: https://github.com/tapio/live-server
[Node.js]: https://nodejs.org/
Expand Down
15 changes: 4 additions & 11 deletions programs/jspaint/TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

### Help

* Resizable panes
* Resizable window
* Link-esque things
* Popups (I'd probably make the text within the popups selectable)
Expand All @@ -26,11 +25,10 @@

* Warning sign for "Save changes to X?" dialog
* Error symbol for error message dialogs
* 3D inset border for inputs - SVG `image-border`?
* 3D inset border for inputs with SVG `image-border` (in [os-gui](https://github.com/1j01/os-gui))
* The window close button uses text; font rendering is not consistent
* The progress bar (Rendering GIF) is left native
* Menu separator spacing
* Minor color differences (0x808080 != 0x7b7b7b) - use a palette for consistency?
* I want to give most things a revisit later on for Pixel Perfection
* Fill bucket and airbrush cursors are supposed to have inverty parts
* Custom cursors in Edge; apparently they require `.cur` files? ugh
Expand Down Expand Up @@ -98,7 +96,7 @@ SVG (or HTML?) with invisible selectable transformed text elements?
* Enlarge menus on touch devices
* Enlarge window titlebar close buttons on touch devices
* Magnifier: on touchscreens, wait until pointerup to zoom
* To detect touchscreen usage, could keep track of whether the last pointermove had any buttons pressed
* To detect touchscreen usage, could keep track of whether the last pointermove had any buttons pressed... or use `pointerType`, right?
* Alternative way to access "Color Eraser" feature without a secondary mouse button?
* Alternative access to functionality that would normally require a keyboard (with a numpad!)
* Numpad +/-: Increase/Decrease brush size, Double/Halve selection size, ...
Expand Down Expand Up @@ -167,7 +165,6 @@ Functionality:
* Show link URLs when you hover over them, in the status bar (because we have a status bar! haha) (there's this API: [event: update-target-url](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#event-update-target-url), which gave me the idea, or it could be implemented with mouse events)
* Recent files (could also be implemented for 98.js.org in the future)
* Create a landing page / home page for the desktop app (similar to https://desktop.webamp.org/ or https://desktop.github.com/) - (perhaps https://desktop.jspaint.app/) - and/or for JS Paint in general (perhaps https://jspaint.app/about/)
* Remove usage of `prompt` (and ideally `alert`/`confirm` too! shouldn't be using these anyways!)
* macOS: `open-file` event, `setRepresentedFilename`, `setDocumentEdited` etc.
* Windows: maybe handle `session-end` event and ask to save?
* Detect if file changes on disk, ask if you want to reload it?
Expand All @@ -182,12 +179,8 @@ Functionality:


* CSS
* DRY, especially button styles - SVG `border-image`?
* Use a CSS preprocessor
* DRY
* Clearer `z-index` handling?
* Color-swap themes (maybe even load Windows theme files)
* Stuff should go in an [OS GUI library](https://github.com/1j01/os-gui) with themes for Windows 98 and other OSes
* DRY, especially button styles, with [os-gui](https://github.com/1j01/os-gui)
* Clearer `z-index` handling, maybe with CSS variables?


* JS
Expand Down
91 changes: 91 additions & 0 deletions programs/jspaint/cypress/cypress-image-snapshot-viewer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// ==UserScript==
// @name Cypress Image Snapshot Viewer
// @namespace https://github.com/1j01/
// @version 0.1
// @description Show diffs of screenshots within the Cypress Dashboard. Works with images from cypress-image-snapshot. To use, press D in the gallery, and then move the mouse over and out of the image.
// @author Isaiah Odhner
// @match https://dashboard.cypress.io/*
// @grant none
// @noframes
// ==/UserScript==

(function() {
'use strict';

let cleanUp = null;

function showDiffView(originalImg) {
if (cleanUp) { cleanUp(); }

var screenshotWidth = originalImg.naturalWidth / 3;
var screenshotHeight = originalImg.naturalHeight;
originalImg.style.opacity = "0";
var img = document.createElement("img");
img.src = originalImg.src;
img.style.position = "absolute";
img.style.left = "0";
img.style.pointerEvents = "all";
img.draggable = false;
img.addEventListener("mouseenter", ()=> {
img.style.left = `${-2 * screenshotWidth}px`;
});
img.addEventListener("mouseleave", ()=> {
img.style.left = "0";
});
var container = document.createElement("div");
container.style.width = `${screenshotWidth}px`;
container.style.height = `${screenshotHeight}px`;
container.style.position = "relative";
container.style.overflow = "hidden";
container.style.margin = "auto";
var outerContainer = document.createElement("div");
outerContainer.style.position = "fixed";
outerContainer.style.display = "flex";
outerContainer.style.left = "0";
outerContainer.style.right = "0";
outerContainer.style.top = "0";
outerContainer.style.bottom = "0";
outerContainer.style.zIndex = "100000";
outerContainer.style.pointerEvents = "none";

outerContainer.appendChild(container);
container.appendChild(img);
document.body.appendChild(outerContainer);

cleanUp = ()=> {
originalImg.style.opacity = "";
container.style.transformOrigin = "center center";
container.style.transition = "opacity 0.2s ease, transform 0.2s ease";
container.style.opacity = 0;
container.style.transform = "scale(0.9)";
setTimeout(()=> {
outerContainer.remove();
}, 500);
cleanUp = null;
};
}

addEventListener("keydown", e=> {
if (e.key === "d") {
if (cleanUp) {
cleanUp();
} else {
var originalImg = document.elementFromPoint(innerWidth/2, innerHeight/2);
if (!originalImg || !originalImg.matches("img")) {
console.warn("Didn't find an image in the middle of the page. Found", originalImg);
return;
}
showDiffView(originalImg);
}
} else if (e.key === "Escape") {
if (cleanUp) { cleanUp(); }
}
});

// mousedown is TAKEN - with stopPropagation, presumably
// (useCapture doesn't help)
addEventListener("pointerdown", (e)=> {
if (cleanUp) { cleanUp(); }
});

})();
5 changes: 5 additions & 0 deletions programs/jspaint/cypress/fixtures/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "[email protected]",
"body": "Fixtures are a great way to mock data for responses to routes"
}
Loading

0 comments on commit b24eeee

Please sign in to comment.