Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d32b82a2bb | ||
|
|
11af21ee6d | ||
|
|
fa4627316d |
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ming-wm"
|
name = "ming-wm"
|
||||||
version = "1.0.1"
|
version = "1.0.3"
|
||||||
repository = "https://github.com/stjet/ming-wm"
|
repository = "https://github.com/stjet/ming-wm"
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|||||||
BIN
bmps/ming-wm.bmp
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
73
bmps/ming-wm.svg
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="210mm"
|
||||||
|
height="297mm"
|
||||||
|
viewBox="0 0 210 297"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
xml:space="preserve"
|
||||||
|
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||||
|
sodipodi:docname="ming-wm.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:zoom="4.3046016"
|
||||||
|
inkscape:cx="449.86742"
|
||||||
|
inkscape:cy="483.20383"
|
||||||
|
inkscape:window-width="706"
|
||||||
|
inkscape:window-height="855"
|
||||||
|
inkscape:window-x="723"
|
||||||
|
inkscape:window-y="34"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1" /><defs
|
||||||
|
id="defs1" /><g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"><rect
|
||||||
|
style="fill:#ffc90e;fill-opacity:1;stroke:none;stroke-width:1.13352"
|
||||||
|
id="rect1"
|
||||||
|
width="10.583"
|
||||||
|
height="10.583"
|
||||||
|
x="116.72247"
|
||||||
|
y="121.45529"
|
||||||
|
inkscape:export-filename="/home/jondough/Downloads/image1.png"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96" /><ellipse
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.53688"
|
||||||
|
id="path1"
|
||||||
|
cx="122.01397"
|
||||||
|
cy="126.7468"
|
||||||
|
rx="3"
|
||||||
|
ry="3.1378791" /><text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.76389px;line-height:1.25;font-family:'Nimbus Roman';-inkscape-font-specification:'Nimbus Roman, ';text-align:start;letter-spacing:0px;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.25"
|
||||||
|
x="123.14632"
|
||||||
|
y="129.68439"
|
||||||
|
id="text1"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan1"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.76389px;font-family:'Nimbus Roman';-inkscape-font-specification:'Nimbus Roman, ';letter-spacing:0px;fill:#000000;stroke:none;stroke-width:1.25"
|
||||||
|
x="123.14632"
|
||||||
|
y="129.68439">wm</tspan></text><text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52778px;line-height:1.25;font-family:'Shippori Mincho';-inkscape-font-specification:'Shippori Mincho';text-align:start;letter-spacing:0px;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.25"
|
||||||
|
x="120.23068"
|
||||||
|
y="128.04678"
|
||||||
|
id="text2"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan2"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52778px;font-family:'Shippori Mincho';-inkscape-font-specification:'Shippori Mincho';fill:#000000;stroke-width:1.25"
|
||||||
|
x="120.23068"
|
||||||
|
y="128.04678">明</tspan></text></g></svg>
|
||||||
|
After Width: | Height: | Size: 3.3 KiB |
BIN
bmps/mingde.bmp
|
Before Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 470 B After Width: | Height: | Size: 374 B |
|
Before Width: | Height: | Size: 438 B After Width: | Height: | Size: 374 B |
BIN
bmps/shippori-mincho/、9.bmp
Normal file
|
After Width: | Height: | Size: 90 B |
BIN
bmps/shippori-mincho/ァ5.bmp
Normal file
|
After Width: | Height: | Size: 222 B |
BIN
bmps/shippori-mincho/ガ3.bmp
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
bmps/shippori-mincho/ギ3.bmp
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
bmps/shippori-mincho/グ3.bmp
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
bmps/shippori-mincho/ゲ3.bmp
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
bmps/shippori-mincho/ゴ1.bmp
Normal file
|
After Width: | Height: | Size: 306 B |
BIN
bmps/shippori-mincho/ザ2.bmp
Normal file
|
After Width: | Height: | Size: 454 B |
BIN
bmps/shippori-mincho/ジ3.bmp
Normal file
|
After Width: | Height: | Size: 378 B |
BIN
bmps/shippori-mincho/ズ3.bmp
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
bmps/shippori-mincho/ゼ3.bmp
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
bmps/shippori-mincho/ゾ3.bmp
Normal file
|
After Width: | Height: | Size: 378 B |
BIN
bmps/shippori-mincho/ダ3.bmp
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
bmps/shippori-mincho/ヂ3.bmp
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
bmps/shippori-mincho/ッ6.bmp
Normal file
|
After Width: | Height: | Size: 198 B |
BIN
bmps/shippori-mincho/ヅ3.bmp
Normal file
|
After Width: | Height: | Size: 378 B |
BIN
bmps/shippori-mincho/デ3.bmp
Normal file
|
After Width: | Height: | Size: 378 B |
BIN
bmps/shippori-mincho/ド3.bmp
Normal file
|
After Width: | Height: | Size: 270 B |
BIN
bmps/shippori-mincho/バ6.bmp
Normal file
|
After Width: | Height: | Size: 294 B |
BIN
bmps/shippori-mincho/パ6.bmp
Normal file
|
After Width: | Height: | Size: 294 B |
BIN
bmps/shippori-mincho/ビ5.bmp
Normal file
|
After Width: | Height: | Size: 250 B |
BIN
bmps/shippori-mincho/ピ4.bmp
Normal file
|
After Width: | Height: | Size: 278 B |
BIN
bmps/shippori-mincho/ブ3.bmp
Normal file
|
After Width: | Height: | Size: 378 B |
BIN
bmps/shippori-mincho/プ0.bmp
Normal file
|
After Width: | Height: | Size: 378 B |
BIN
bmps/shippori-mincho/ボ3.bmp
Normal file
|
After Width: | Height: | Size: 378 B |
BIN
bmps/shippori-mincho/ポ4.bmp
Normal file
|
After Width: | Height: | Size: 342 B |
BIN
bmps/shippori-mincho/ャ5.bmp
Normal file
|
After Width: | Height: | Size: 250 B |
BIN
bmps/shippori-mincho/ュ8.bmp
Normal file
|
After Width: | Height: | Size: 166 B |
BIN
bmps/shippori-mincho/ョ7.bmp
Normal file
|
After Width: | Height: | Size: 154 B |
BIN
bmps/shippori-mincho/全0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/創0.bmp
Normal file
|
After Width: | Height: | Size: 582 B |
BIN
bmps/shippori-mincho/咲0.bmp
Normal file
|
After Width: | Height: | Size: 582 B |
BIN
bmps/shippori-mincho/声0.bmp
Normal file
|
After Width: | Height: | Size: 582 B |
BIN
bmps/shippori-mincho/子1.bmp
Normal file
|
After Width: | Height: | Size: 538 B |
BIN
bmps/shippori-mincho/年0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/度0.bmp
Normal file
|
After Width: | Height: | Size: 582 B |
|
Before Width: | Height: | Size: 582 B After Width: | Height: | Size: 582 B |
BIN
bmps/shippori-mincho/思1.bmp
Normal file
|
After Width: | Height: | Size: 538 B |
BIN
bmps/shippori-mincho/教0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/某0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/森0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/猫0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/的0.bmp
Normal file
|
After Width: | Height: | Size: 582 B |
BIN
bmps/shippori-mincho/眩0.bmp
Normal file
|
After Width: | Height: | Size: 582 B |
BIN
bmps/shippori-mincho/穴0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/窓0.bmp
Normal file
|
After Width: | Height: | Size: 582 B |
BIN
bmps/shippori-mincho/義0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/老0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/胸0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/返0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/過0.bmp
Executable file
|
After Width: | Height: | Size: 630 B |
BIN
bmps/shippori-mincho/降0.bmp
Normal file
|
After Width: | Height: | Size: 582 B |
BIN
bmps/shippori-mincho/馬0.bmp
Normal file
|
After Width: | Height: | Size: 582 B |
BIN
bmps/shippori-mincho/騒0.bmp
Normal file
|
After Width: | Height: | Size: 630 B |
4
build.rs
@@ -15,8 +15,7 @@ fn font_chars_to_alphas(dir: &str) {
|
|||||||
if file_name.len() < 2 {
|
if file_name.len() < 2 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if file_name[1] == "bmp" {
|
if file_name[1] == "bmp" && !path.is_dir() {
|
||||||
if !path.is_dir() {
|
|
||||||
let mut ch: Vec<Vec<String>> = Vec::new();
|
let mut ch: Vec<Vec<String>> = Vec::new();
|
||||||
let b = BMP::new_from_file(&path.clone().into_os_string().into_string().unwrap()).unwrap();
|
let b = BMP::new_from_file(&path.clone().into_os_string().into_string().unwrap()).unwrap();
|
||||||
let dib_header = b.get_dib_header().unwrap();
|
let dib_header = b.get_dib_header().unwrap();
|
||||||
@@ -45,7 +44,6 @@ fn font_chars_to_alphas(dir: &str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
//hash + "salt" password and add to build
|
//hash + "salt" password and add to build
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 948 KiB After Width: | Height: | Size: 906 KiB |
26
docs/system/keys.md
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
Relevant section taken from `src/bin/main.rs`:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn key_to_char(key: Key) -> Option<KeyChar> {
|
||||||
|
match key {
|
||||||
|
Key::Char('\n') => Some(KeyChar::Press('𐘂')),
|
||||||
|
Key::Char(c) => Some(KeyChar::Press(c)),
|
||||||
|
Key::Alt(c) => Some(KeyChar::Alt(c)),
|
||||||
|
Key::Ctrl(c) => Some(KeyChar::Ctrl(c)),
|
||||||
|
Key::Backspace => Some(KeyChar::Press('𐘁')),
|
||||||
|
Key::Esc => Some(KeyChar::Press('𐘃')),
|
||||||
|
Key::Up => Some(KeyChar::Press('𐙘')),
|
||||||
|
Key::Down => Some(KeyChar::Press('𐘞')),
|
||||||
|
Key::Left => Some(KeyChar::Press('𐙣')),
|
||||||
|
Key::Right => Some(KeyChar::Press('𐙥')),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The special keys backspace, enter, escape, and the arrows, are represented by a single Linear A char. For ease, there are [methods](https://docs.rs/ming-wm-lib/latest/ming_wm_lib/messages/struct.KeyPress.html) to check whether a key press is a backspace, enter, etc, without pasting the Linear A into the code.
|
||||||
|
|
||||||
|
Although the arrow keys are supported, please try and support the Vim `hjkl` if possible!
|
||||||
|
|
||||||
|
The `Press` events are sent as `WindowMessage::KeyPress(KeyPress)`, and the `Ctrl` events are sent as `WindowMessage::CtrlKeyPress(KeyPress)`. Any keys pressed along with the Alt key are not passed to the windows.
|
||||||
|
|
||||||
@@ -16,5 +16,9 @@
|
|||||||
- Alt+J: Move window to bottom edge
|
- Alt+J: Move window to bottom edge
|
||||||
- Alt+K: Move window to top edge
|
- Alt+K: Move window to top edge
|
||||||
- Alt+L: Move window to right edge
|
- Alt+L: Move window to right edge
|
||||||
|
- Alt+n: Expand window width
|
||||||
|
- Alt+m: Expand window height
|
||||||
|
- Alt+N: Shrink window width
|
||||||
|
- Alt+M: Shrink window height
|
||||||
- Alt+1, Alt+2, ..., Alt+[n], ..., Alt+9: Switch to workspace [n]
|
- Alt+1, Alt+2, ..., Alt+[n], ..., Alt+9: Switch to workspace [n]
|
||||||
- Alt+shift+1, Alt+shift+2, ..., Alt+shift+[n], ..., Alt+shift+9: Move window to workspace [n]
|
- Alt+shift+1, Alt+shift+2, ..., Alt+shift+[n], ..., Alt+shift+9: Move window to workspace [n]
|
||||||
|
|||||||
@@ -101,8 +101,17 @@ mv target/release/mingMisc_Example /usr/bin/mingMisc_Example #or whatever direct
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
## Now what?
|
||||||
|
|
||||||
|
Handle various inputs in `handle_message`, and have it mutate the state. Draw the relevant state in `draw`. Not too hard, eh?
|
||||||
|
|
||||||
|
Besides looking at the examples (Koxinga, `src/bin`), read the [ming-wm-lib docs](https://docs.rs/ming-wm-lib)!
|
||||||
|
|
||||||
|
Also, `docs/system/keys.md` may be useful.
|
||||||
|
|
||||||
## Tips
|
## Tips
|
||||||
|
|
||||||
- For windows that are separate binaries, the Elm Architecture obviously cannot be enforced (unless the window is written in Rust and uses the `ming-wm-lib`. However, the design of the IPC and the nature of the window manager being keyboard-driven makes it so using the Elm Architecture is highly recommended.
|
- For windows that are separate binaries, the Elm Architecture obviously cannot be enforced (unless the window is written in Rust and uses the `ming-wm-lib`. However, the design of the IPC and the nature of the window manager being keyboard-driven makes it so using the Elm Architecture is highly recommended.
|
||||||
- Since the window manager currently queries and reads the responses to/from window binaries in the main thread, while the response is being waited for, the window manager is "frozen". Therefore, time-consuming tasks (>1 second) should not be done in the main thread, but rather a separate thread. For example, the ming-wm audio player (`src/bin/audio_player.rs`) does the time-consuming process of reading audio files in a separate thread to not hold up the window manager, and provide quick responses.
|
- Since the window manager currently queries and reads the responses to/from window binaries in the main thread, while the response is being waited for, the window manager is "frozen". Therefore, time-consuming tasks (>1 second) should not be done in the main thread, but rather a separate thread. For example, the ming-wm audio player (`src/bin/audio_player.rs`) does the time-consuming process of reading audio files in a separate thread to not hold up the window manager, and provide quick responses.
|
||||||
|
- Window panics will be logged to `~/.local/share/ming-wm/logs.txt`.
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ Barebones file explorer.
|
|||||||
|
|
||||||
## Navigation
|
## Navigation
|
||||||
|
|
||||||
- `j`: Move down
|
- `j` (or down arrow): Move down
|
||||||
- `k`: Move up
|
- `k` (or up arrow): Move up
|
||||||
- `i`: See info about current file / directory (press any key to escape info screen)
|
- `i`: See info about current file / directory (press any key to escape info screen)
|
||||||
- `Enter`: Go into directory
|
- `Enter`: Go into directory
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ It is probably best to read a Vim tutorial for the basics. All supportd keystrok
|
|||||||
- `t[abe] <file>`, `[tab]n`, `[tab]p`
|
- `t[abe] <file>`, `[tab]n`, `[tab]p`
|
||||||
- `q[uit]`
|
- `q[uit]`
|
||||||
- `w[rite]`
|
- `w[rite]`
|
||||||
|
- `/<query>`
|
||||||
|
|
||||||
Tab completion is supported for the `<file>` argument.
|
Tab completion is supported for the `<file>` argument.
|
||||||
|
|
||||||
@@ -23,15 +24,17 @@ Tab completion is supported for the `<file>` argument.
|
|||||||
- `r`
|
- `r`
|
||||||
- `dd`
|
- `dd`
|
||||||
- `dw`
|
- `dw`
|
||||||
|
- `d$`
|
||||||
- `G`
|
- `G`
|
||||||
- `gg`
|
- `gg`
|
||||||
- `<number>gg`
|
- `<number>gg`
|
||||||
- `f<char>`
|
- `f<char>`
|
||||||
- `F<char>`
|
- `F<char>`
|
||||||
- `x`
|
- `x`
|
||||||
- `h`, `j`, `k`, `l`
|
- `h` (or left arrow), `j` (or down arrow), `k` (or up arrow), `l` (or right arrow)
|
||||||
- `<num>h`, `<num>j`, `<num>k`, `<num>l`
|
- `<num>h`, `<num>j` (or down arrow), `<num>k` (or up arrow), `<num>l`
|
||||||
- `0`, `^`, `$`
|
- `0`, `^`, `$`
|
||||||
|
- `%`
|
||||||
|
|
||||||
### Malvim Specific
|
### Malvim Specific
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ The start menu, which can be opened and closed with the [Alt+s shortcut](../syst
|
|||||||
|
|
||||||
## Navigation
|
## Navigation
|
||||||
|
|
||||||
Use the 'j' and 'k' keys to move down and up respectively. Going down past the last option returns the selection to the first option, and vice versa (it loops).
|
Use the 'j' and 'k' keys to move down and up respectively. The up and down arrow keys can also be used. Going down past the last option returns the selection to the first option, and vice versa (it loops).
|
||||||
|
|
||||||
Hitting the 'enter' key will either open a subfolder containing window-likes, if a category is selected, or the corresponding window-like, if a window-like is selected. It may also exit a subfolder and return to the category selection if "Back" is selected and 'enter' is hit. There is another special case: hitting 'enter' while the "Logout" option is selected will, as the name implies, logout and return to the lock screen (this does not log out of the Linux user!).
|
Hitting the 'enter' key will either open a subfolder containing window-likes, if a category is selected, or the corresponding window-like, if a window-like is selected. It may also exit a subfolder and return to the category selection if "Back" is selected and 'enter' is hit. There is another special case: hitting 'enter' while the "Logout" option is selected will, as the name implies, logout and return to the lock screen (this does not log out of the Linux user!).
|
||||||
|
|
||||||
For faster navigation, hitting any lower-case letter (besides 'j' and 'k') will move the selection to the next option that starts with that letter (non-looping). For example, when first opening the start menu, hitting 'e' will move the selection to "Editing". Hitting any upper-case letter will move the selection to any previous option that starts with that letter (also non-looping). For example, when initially opening the start menu, the selected option is "About". After hitting 'j' (moving down), hitting 'A' will return the selection to "About".
|
For faster navigation, hitting any lower-case letter (besides 'j' and 'k') will move the selection to the next option that starts with that letter (non-looping). For example, when first opening the start menu, hitting 'e' will move the selection to "Editing". Hitting any upper-case letter will move the selection to any previous option that starts with that letter (also non-looping). For example, when initially opening the start menu, the selected option is "About". After hitting 'j' (moving down), hitting 'A' will return the selection to "About".
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ The terminal starts off in INPUT mode, which allows entering commands to run. If
|
|||||||
|
|
||||||
In INPUT mode, commands can be freely typed. There are a few special control sequences:
|
In INPUT mode, commands can be freely typed. There are a few special control sequences:
|
||||||
|
|
||||||
- `ctrl+p`: Equivalent to the up arrow in most terminals. Brings up the previous command in the command history, and so on.
|
- `ctrl+p` (or up arrow): Equivalent to the up arrow in most terminals. Brings up the previous command in the command history, and so on.
|
||||||
- `ctrl+n`: Equivalent to the down arrow in most terminals. Either clears the current input if not in a previous command, else brings up the next command in the command history.
|
- `ctrl+n` (or down arrow): Equivalent to the down arrow in most terminals. Either clears the current input if not in a previous command, else brings up the next command in the command history.
|
||||||
|
|
||||||
Tab completion is also supported, though only for file/directory paths.
|
Tab completion is also supported, though only for file/directory paths.
|
||||||
|
|
||||||
|
|||||||
9
install
@@ -1,10 +1,11 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
rm -rf /usr/local/bin/ming_bmps
|
rm -rf /usr/local/bin/ming_bmps
|
||||||
cp -r ./bmps /usr/local/bin/ming_bmps
|
cp -r ./bmps /usr/local/bin/ming_bmps
|
||||||
rm -rf /usr/local/bin/ming_bmps/nimbus-roman/*.bmp
|
rm -f /usr/local/bin/ming_bmps/nimbus-roman/*.bmp
|
||||||
rm -rf /usr/local/bin/ming_bmps/nimbus-romano/*.bmp
|
rm -f /usr/local/bin/ming_bmps/nimbus-romano/*.bmp
|
||||||
rm -rf /usr/local/bin/ming_bmps/shippori-mincho/*.bmp
|
rm -f /usr/local/bin/ming_bmps/shippori-mincho/*.bmp
|
||||||
rm /usr/local/bin/ming_bmps/*1440x842.bmp
|
rm -f /usr/local/bin/ming_bmps/*1440x842.bmp
|
||||||
|
rm -f /usr/local/bin/ming_bmps/*.svg
|
||||||
rm -rf /usr/local/bin/ming_docs
|
rm -rf /usr/local/bin/ming_docs
|
||||||
cp -r ./docs /usr/local/bin/ming_docs
|
cp -r ./docs /usr/local/bin/ming_docs
|
||||||
rm -rf /usr/local/bin/ming_docs/images
|
rm -rf /usr/local/bin/ming_docs/images
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
rm -rf ~/.local/bin/ming_bmps
|
rm -rf ~/.local/bin/ming_bmps
|
||||||
cp -r ./bmps ~/.local/bin/ming_bmps
|
cp -r ./bmps ~/.local/bin/ming_bmps
|
||||||
rm -rf ~/.local/bin/ming_bmps/nimbus-roman/*.bmp
|
rm -f ~/.local/bin/ming_bmps/nimbus-roman/*.bmp
|
||||||
rm -rf ~/.local/bin/ming_bmps/nimbus-romano/*.bmp
|
rm -f ~/.local/bin/ming_bmps/nimbus-romano/*.bmp
|
||||||
rm -rf ~/.local/bin/ming_bmps/shippori-mincho/*.bmp
|
rm -f ~/.local/bin/ming_bmps/shippori-mincho/*.bmp
|
||||||
rm ~/.local/bin/ming_bmps/*1440x842.bmp
|
rm -f ~/.local/bin/ming_bmps/*1440x842.bmp
|
||||||
|
rm -f ~/.local/bin/ming_bmps/*.svg
|
||||||
rm -rf ~/.local/bin/ming_docs
|
rm -rf ~/.local/bin/ming_docs
|
||||||
cp -r ./docs ~/.local/bin/ming_docs
|
cp -r ./docs ~/.local/bin/ming_docs
|
||||||
rm -rf ~/.local/bin/ming_docs/images
|
rm -rf ~/.local/bin/ming_docs/images
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ming-wm-lib"
|
name = "ming-wm-lib"
|
||||||
version = "0.1.4"
|
version = "0.1.6"
|
||||||
repository = "https://github.com/stjet/ming-wm"
|
repository = "https://github.com/stjet/ming-wm"
|
||||||
description = "library for building windows for ming-wm in rust"
|
description = "library for building windows for ming-wm in rust"
|
||||||
|
readme = "README.md"
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1,6 @@
|
|||||||
Library for building [ming-wm](https://github.com/stjet/ming-wm) windows in Rust.
|
Library for building [ming-wm](https://github.com/stjet/ming-wm) windows in Rust.
|
||||||
|
|
||||||
|
Documentation [here](https://docs.rs/ming-wm-lib).
|
||||||
|
|
||||||
|
The most likely usage of this crate is to implement the [WindowLike trait](https://docs.rs/ming-wm-lib/latest/ming_wm_lib/window_manager_types/trait.WindowLike.html), and then set up [IPC](https://docs.rs/ming-wm-lib/latest/ming_wm_lib/ipc/fn.listen.html) (which automatically handles serialisation).
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ pub trait WindowLike {
|
|||||||
|
|
||||||
const LOG: bool = false;
|
const LOG: bool = false;
|
||||||
|
|
||||||
|
/// Listen and process what the window manager writes to our stdin
|
||||||
pub fn listen(mut window_like: impl WindowLike) {
|
pub fn listen(mut window_like: impl WindowLike) {
|
||||||
panic::set_hook(Box::new(|panic_info| {
|
panic::set_hook(Box::new(|panic_info| {
|
||||||
let (filename, line) = panic_info.location().map(|l| (l.file(), l.line())).unwrap_or(("<unknown>", 0));
|
let (filename, line) = panic_info.location().map(|l| (l.file(), l.line())).unwrap_or(("<unknown>", 0));
|
||||||
@@ -57,22 +58,22 @@ pub fn listen(mut window_like: impl WindowLike) {
|
|||||||
let arg = &parts.collect::<Vec<&str>>().join(" ");
|
let arg = &parts.collect::<Vec<&str>>().join(" ");
|
||||||
let output = match method {
|
let output = match method {
|
||||||
"handle_message" => {
|
"handle_message" => {
|
||||||
format!("{}", &window_like.handle_message(WindowMessage::deserialize(arg).unwrap()).serialize())
|
window_like.handle_message(WindowMessage::deserialize(arg).unwrap()).serialize().to_string()
|
||||||
},
|
},
|
||||||
"draw" => {
|
"draw" => {
|
||||||
format!("{}", &window_like.draw(&ThemeInfo::deserialize(arg).unwrap()).serialize().replace("\n", ""))
|
window_like.draw(&ThemeInfo::deserialize(arg).unwrap()).serialize().replace("\n", "").to_string()
|
||||||
},
|
},
|
||||||
"title" => {
|
"title" => {
|
||||||
format!("{}", window_like.title())
|
window_like.title().to_string()
|
||||||
},
|
},
|
||||||
"resizable" => {
|
"resizable" => {
|
||||||
format!("{}", window_like.resizable())
|
window_like.resizable().to_string()
|
||||||
},
|
},
|
||||||
"subtype" => {
|
"subtype" => {
|
||||||
format!("{}", &window_like.subtype().serialize())
|
window_like.subtype().serialize().to_string()
|
||||||
},
|
},
|
||||||
"ideal_dimensions" => {
|
"ideal_dimensions" => {
|
||||||
format!("{}", &window_like.ideal_dimensions(Dimensions::deserialize(arg).unwrap()).serialize())
|
window_like.ideal_dimensions(Dimensions::deserialize(arg).unwrap()).serialize().to_string()
|
||||||
},
|
},
|
||||||
_ => String::new(),
|
_ => String::new(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use std::io::Write;
|
|||||||
|
|
||||||
use crate::dirs::data_dir;
|
use crate::dirs::data_dir;
|
||||||
|
|
||||||
|
/// Writes to `<XDG data directory>/ming-wm/logs.txt`. Use only for debugging!
|
||||||
pub fn log(message: &str) {
|
pub fn log(message: &str) {
|
||||||
let data = data_dir().unwrap().into_os_string().into_string().unwrap();
|
let data = data_dir().unwrap().into_os_string().into_string().unwrap();
|
||||||
let _ = create_dir(format!("{}/ming-wm", data));
|
let _ = create_dir(format!("{}/ming-wm", data));
|
||||||
|
|||||||
@@ -4,12 +4,14 @@ use std::vec::Vec;
|
|||||||
use crate::framebuffer_types::Dimensions;
|
use crate::framebuffer_types::Dimensions;
|
||||||
use crate::window_manager_types::{ WindowLike, KeyChar };
|
use crate::window_manager_types::{ WindowLike, KeyChar };
|
||||||
|
|
||||||
|
/// Window manager internal usage
|
||||||
pub enum WindowManagerMessage {
|
pub enum WindowManagerMessage {
|
||||||
KeyChar(KeyChar),
|
KeyChar(KeyChar),
|
||||||
Touch(usize, usize),
|
Touch(usize, usize),
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Window manager internal usage
|
||||||
pub type WindowBox = Box<dyn WindowLike>;
|
pub type WindowBox = Box<dyn WindowLike>;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -50,10 +52,50 @@ impl WindowMessageResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//struct because may add more fields later (so struct is better for code backward compatibility)
|
||||||
pub struct KeyPress {
|
pub struct KeyPress {
|
||||||
pub key: char,
|
pub key: char,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl KeyPress {
|
||||||
|
pub fn is_enter(&self) -> bool {
|
||||||
|
self.key == '𐘂'
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_backspace(&self) -> bool {
|
||||||
|
self.key == '𐘁'
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_escape(&self) -> bool {
|
||||||
|
self.key == '𐘃'
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_up_arrow(&self) -> bool {
|
||||||
|
self.key == '𐙘'
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_down_arrow(&self) -> bool {
|
||||||
|
self.key == '𐘞'
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_left_arrow(&self) -> bool {
|
||||||
|
self.key == '𐙣'
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_right_arrow(&self) -> bool {
|
||||||
|
self.key == '𐙥'
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_arrow(&self) -> bool {
|
||||||
|
self.is_up_arrow() || self.is_down_arrow() || self.is_left_arrow() || self.is_right_arrow()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is not enter, backspace, arrow keys (the Linear A stuff)
|
||||||
|
pub fn is_regular(&self) -> bool {
|
||||||
|
!self.is_enter() && !self.is_backspace() && !self.is_escape() && !self.is_arrow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
pub enum Direction {
|
pub enum Direction {
|
||||||
Left,
|
Left,
|
||||||
@@ -87,7 +129,7 @@ pub type WindowsVec = Vec<(usize, String)>;
|
|||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum InfoType {
|
pub enum InfoType {
|
||||||
//let taskbar know what the current windows in the workspace are
|
/// Let taskbar know what the current windows in the workspace are
|
||||||
WindowsInWorkspace(WindowsVec, usize), //Vec<(id, name)>, focused id
|
WindowsInWorkspace(WindowsVec, usize), //Vec<(id, name)>, focused id
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
@@ -102,7 +144,8 @@ pub enum WindowMessage {
|
|||||||
Unfocus,
|
Unfocus,
|
||||||
FocusClick,
|
FocusClick,
|
||||||
ChangeDimensions(Dimensions),
|
ChangeDimensions(Dimensions),
|
||||||
Touch(usize, usize), //for onscreen keyboard only
|
/// For onscreen keyboard only
|
||||||
|
Touch(usize, usize),
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,10 +39,10 @@ fn option_to_string<T: Display>(option: &Option<T>) -> String {
|
|||||||
fn get_color(serialized: &str) -> Result<[u8; 3], ()> {
|
fn get_color(serialized: &str) -> Result<[u8; 3], ()> {
|
||||||
let rgb = serialized.split("\x1F");
|
let rgb = serialized.split("\x1F");
|
||||||
let mut color = [0; 3];
|
let mut color = [0; 3];
|
||||||
let mut c_i = 0;
|
|
||||||
//won't return error if rgb is 0, 1, or 2 elements.
|
//won't return error if rgb is 0, 1, or 2 elements.
|
||||||
//I guess that's okay, since it doesn't panic either
|
//I guess that's okay, since it doesn't panic either
|
||||||
for c in rgb {
|
//c_i is the loop counter. enumerate(), you are awesome
|
||||||
|
for (c_i, c) in rgb.enumerate() {
|
||||||
if c_i == 3 {
|
if c_i == 3 {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
@@ -51,7 +51,6 @@ fn get_color(serialized: &str) -> Result<[u8; 3], ()> {
|
|||||||
} else {
|
} else {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
c_i += 1;
|
|
||||||
}
|
}
|
||||||
Ok(color)
|
Ok(color)
|
||||||
}
|
}
|
||||||
@@ -68,7 +67,7 @@ fn get_two_array(serialized: &str) -> Result<[usize; 2], ()> {
|
|||||||
}
|
}
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
return Ok(a);
|
Ok(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Serializable {
|
pub trait Serializable {
|
||||||
@@ -87,9 +86,8 @@ impl Serializable for ThemeInfo {
|
|||||||
let serialized = if serialized.ends_with("\n") { &serialized[..serialized.len() - 1] } else { serialized };
|
let serialized = if serialized.ends_with("\n") { &serialized[..serialized.len() - 1] } else { serialized };
|
||||||
let mut theme_info: ThemeInfo = Default::default();
|
let mut theme_info: ThemeInfo = Default::default();
|
||||||
let arrays = serialized.split(":");
|
let arrays = serialized.split(":");
|
||||||
let mut a_i = 0;
|
|
||||||
//won't error or panic if less than 9... rest will just be black by default I guess
|
//won't error or panic if less than 9... rest will just be black by default I guess
|
||||||
for a in arrays {
|
for (a_i, a) in arrays.enumerate() {
|
||||||
if a_i == 9 {
|
if a_i == 9 {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
@@ -127,7 +125,6 @@ impl Serializable for ThemeInfo {
|
|||||||
if a_i == 8 {
|
if a_i == 8 {
|
||||||
return Ok(theme_info);
|
return Ok(theme_info);
|
||||||
}
|
}
|
||||||
a_i += 1;
|
|
||||||
}
|
}
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
@@ -220,7 +217,7 @@ impl Serializable for DrawInstructions {
|
|||||||
match self {
|
match self {
|
||||||
//use \x1E (record separator) because it won't be in strings. it better fucking not be at least
|
//use \x1E (record separator) because it won't be in strings. it better fucking not be at least
|
||||||
DrawInstructions::Rect(p, d, c) => format!("Rect/{}\x1E{}\x1E{}", array_to_string(p), array_to_string(d), array_to_string(c)),
|
DrawInstructions::Rect(p, d, c) => format!("Rect/{}\x1E{}\x1E{}", array_to_string(p), array_to_string(d), array_to_string(c)),
|
||||||
DrawInstructions::Text(p, vs, s, c1, c2, ou1, ou2) => format!("Text/{}\x1E{}\x1E{}\x1E{}\x1E{}\x1E{}\x1E{}", array_to_string(p), array_to_string(&vs), s, array_to_string(c1), array_to_string(c2), option_to_string(ou1), option_to_string(ou2)),
|
DrawInstructions::Text(p, vs, s, c1, c2, ou1, ou2) => format!("Text/{}\x1E{}\x1E{}\x1E{}\x1E{}\x1E{}\x1E{}", array_to_string(p), array_to_string(vs), s, array_to_string(c1), array_to_string(c2), option_to_string(ou1), option_to_string(ou2)),
|
||||||
DrawInstructions::Gradient(p, d, c1, c2, u) => format!("Gradient/{}\x1E{}\x1E{}\x1E{}\x1E{}", array_to_string(p), array_to_string(d), array_to_string(c1), array_to_string(c2), u),
|
DrawInstructions::Gradient(p, d, c1, c2, u) => format!("Gradient/{}\x1E{}\x1E{}\x1E{}\x1E{}", array_to_string(p), array_to_string(d), array_to_string(c1), array_to_string(c2), u),
|
||||||
DrawInstructions::Bmp(p, s, b) => format!("Bmp/{}\x1E{}\x1E{}", array_to_string(p), s, b),
|
DrawInstructions::Bmp(p, s, b) => format!("Bmp/{}\x1E{}\x1E{}", array_to_string(p), s, b),
|
||||||
DrawInstructions::Circle(p, u, c) => format!("Circle/{}\x1E{}\x1E{}", array_to_string(p), u, array_to_string(c)),
|
DrawInstructions::Circle(p, u, c) => format!("Circle/{}\x1E{}\x1E{}", array_to_string(p), u, array_to_string(c)),
|
||||||
@@ -674,8 +671,7 @@ impl Serializable for WindowMessage {
|
|||||||
}
|
}
|
||||||
let mut w_tuple: (usize, String) = Default::default();
|
let mut w_tuple: (usize, String) = Default::default();
|
||||||
let mut w_vec = Vec::new();
|
let mut w_vec = Vec::new();
|
||||||
let mut i = 0;
|
for (i, a) in arg2.unwrap().split("\x1F").enumerate() {
|
||||||
for a in arg2.unwrap().split("\x1F") {
|
|
||||||
if i % 2 == 0 {
|
if i % 2 == 0 {
|
||||||
if let Ok(n) = a.parse() {
|
if let Ok(n) = a.parse() {
|
||||||
w_tuple.0 = n;
|
w_tuple.0 = n;
|
||||||
@@ -684,7 +680,6 @@ impl Serializable for WindowMessage {
|
|||||||
w_tuple.1 = a.to_string();
|
w_tuple.1 = a.to_string();
|
||||||
w_vec.push(w_tuple.clone());
|
w_vec.push(w_tuple.clone());
|
||||||
}
|
}
|
||||||
i += 1;
|
|
||||||
}
|
}
|
||||||
let arg2 = parts2.next();
|
let arg2 = parts2.next();
|
||||||
if arg2.is_none() {
|
if arg2.is_none() {
|
||||||
|
|||||||
@@ -97,12 +97,13 @@ const THEME_INFOS: [(Themes, ThemeInfo); 5] = [
|
|||||||
//
|
//
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/// Window manager internal usage
|
||||||
pub fn get_theme_info(theme: &Themes) -> Option<ThemeInfo> {
|
pub fn get_theme_info(theme: &Themes) -> Option<ThemeInfo> {
|
||||||
for pair in THEME_INFOS {
|
for pair in THEME_INFOS {
|
||||||
if &pair.0 == theme {
|
if &pair.0 == theme {
|
||||||
return Some(pair.1);
|
return Some(pair.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return None;
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ pub trait Substring {
|
|||||||
fn substring(&self, start: usize, end: usize) -> &str;
|
fn substring(&self, start: usize, end: usize) -> &str;
|
||||||
fn remove(&self, index: usize, len: usize) -> String;
|
fn remove(&self, index: usize, len: usize) -> String;
|
||||||
fn remove_last(&self) -> String;
|
fn remove_last(&self) -> String;
|
||||||
|
fn find_substring(&self, substr: &str) -> Option<usize>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Substring for String {
|
impl Substring for String {
|
||||||
@@ -29,6 +30,14 @@ impl Substring for String {
|
|||||||
byte_end += char_length;
|
byte_end += char_length;
|
||||||
}
|
}
|
||||||
&self[byte_start..byte_end]
|
&self[byte_start..byte_end]
|
||||||
|
/*
|
||||||
|
let mut result = String::new();
|
||||||
|
let mut chars = self.chars().skip(start);
|
||||||
|
for _i in 0..(end - start) {
|
||||||
|
result += &chars.next().unwrap().to_string();
|
||||||
|
}
|
||||||
|
result
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove(&self, index: usize, len: usize) -> String {
|
fn remove(&self, index: usize, len: usize) -> String {
|
||||||
@@ -38,13 +47,26 @@ impl Substring for String {
|
|||||||
fn remove_last(&self) -> String {
|
fn remove_last(&self) -> String {
|
||||||
self.substring(0, self.chars().count() - 1).to_string()
|
self.substring(0, self.chars().count() - 1).to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_substring(&self, substr: &str) -> Option<usize> {
|
||||||
|
//slightly inefficient
|
||||||
|
let substr_len = substr.chars().count();
|
||||||
|
let self_len = self.chars().count();
|
||||||
|
if substr_len <= self_len {
|
||||||
|
for start in 0..=(self_len - substr_len) {
|
||||||
|
if self.substring(start, start + substr_len) == substr {
|
||||||
|
return Some(start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//the tuple is first, line #, actual line
|
//the tuple is first, line #, actual line
|
||||||
pub fn calc_actual_lines<'a>(lines: impl Iterator<Item = &'a String>, max_chars_per_line: usize, one_extra: bool) -> Vec<(bool, usize, String)> {
|
pub fn calc_actual_lines<'a>(lines: impl Iterator<Item = &'a String>, max_chars_per_line: usize, one_extra: bool) -> Vec<(bool, usize, String)> {
|
||||||
let mut actual_lines = Vec::new();
|
let mut actual_lines = Vec::new();
|
||||||
let mut line_num = 0;
|
for (line_num, real_line) in lines.enumerate() {
|
||||||
for real_line in lines {
|
|
||||||
let mut line = real_line.to_string() + if one_extra { " " } else { "" };
|
let mut line = real_line.to_string() + if one_extra { " " } else { "" };
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
loop {
|
loop {
|
||||||
@@ -62,7 +84,6 @@ pub fn calc_actual_lines<'a>(lines: impl Iterator<Item = &'a String>, max_chars_
|
|||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
line_num += 1;
|
|
||||||
}
|
}
|
||||||
actual_lines
|
actual_lines
|
||||||
}
|
}
|
||||||
@@ -132,7 +153,7 @@ pub fn hex_to_u8(c1: char, c2: char) -> u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_hex(c: char) -> bool {
|
pub fn is_hex(c: char) -> bool {
|
||||||
HEX_CHARS.iter().position(|hc| hc == &c).is_some()
|
HEX_CHARS.iter().any(|hc| hc == &c)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn point_inside(point: Point, top_left: Point, size: Dimensions) -> bool {
|
pub fn point_inside(point: Point, top_left: Point, size: Dimensions) -> bool {
|
||||||
@@ -193,4 +214,3 @@ pub fn path_autocomplete(current_path: &str, partial_path: &str) -> Option<Strin
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,8 +61,7 @@ impl WindowLike for FileExplorer {
|
|||||||
WindowMessageResponse::JustRedraw
|
WindowMessageResponse::JustRedraw
|
||||||
},
|
},
|
||||||
WindowMessage::KeyPress(key_press) => {
|
WindowMessage::KeyPress(key_press) => {
|
||||||
self.state = State::List;
|
if key_press.is_enter() && self.state == State::List {
|
||||||
if key_press.key == '𐘂' { //the enter key
|
|
||||||
if self.current_dir_contents.len() > 0 {
|
if self.current_dir_contents.len() > 0 {
|
||||||
let selected_entry = &self.current_dir_contents[self.position];
|
let selected_entry = &self.current_dir_contents[self.position];
|
||||||
if !selected_entry.is_file {
|
if !selected_entry.is_file {
|
||||||
@@ -74,8 +73,9 @@ impl WindowLike for FileExplorer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
WindowMessageResponse::DoNothing
|
WindowMessageResponse::DoNothing
|
||||||
} else if key_press.key == 'j' || key_press.key == 'k' {
|
} else if key_press.key == 'j' || key_press.is_down_arrow() || key_press.key == 'k' || key_press.is_up_arrow() {
|
||||||
if key_press.key == 'j' {
|
self.state = State::List;
|
||||||
|
if key_press.key == 'j' || key_press.is_down_arrow() {
|
||||||
//down
|
//down
|
||||||
if self.position == self.current_dir_contents.len() - 1 {
|
if self.position == self.current_dir_contents.len() - 1 {
|
||||||
self.position = 0;
|
self.position = 0;
|
||||||
@@ -94,7 +94,7 @@ impl WindowLike for FileExplorer {
|
|||||||
let max_height = self.dimensions[1] - HEIGHT;
|
let max_height = self.dimensions[1] - HEIGHT;
|
||||||
if self.position > self.top_position {
|
if self.position > self.top_position {
|
||||||
let current_height = (self.position - self.top_position + 1) * HEIGHT;
|
let current_height = (self.position - self.top_position + 1) * HEIGHT;
|
||||||
if current_height > self.dimensions[1] {
|
if current_height > max_height {
|
||||||
//somehow this is slightly off sometimes
|
//somehow this is slightly off sometimes
|
||||||
self.top_position += (current_height - max_height).div_ceil(HEIGHT);
|
self.top_position += (current_height - max_height).div_ceil(HEIGHT);
|
||||||
}
|
}
|
||||||
@@ -103,13 +103,22 @@ impl WindowLike for FileExplorer {
|
|||||||
};
|
};
|
||||||
WindowMessageResponse::JustRedraw
|
WindowMessageResponse::JustRedraw
|
||||||
} else if key_press.key == 'i' {
|
} else if key_press.key == 'i' {
|
||||||
|
if self.state == State::Info {
|
||||||
|
self.state = State::List;
|
||||||
|
} else {
|
||||||
self.state = State::Info;
|
self.state = State::Info;
|
||||||
let selected_entry = &self.current_dir_contents[self.position];
|
let selected_entry = &self.current_dir_contents[self.position];
|
||||||
self.metadata = Some(metadata(&selected_entry.path).unwrap());
|
self.metadata = Some(metadata(&selected_entry.path).unwrap());
|
||||||
|
}
|
||||||
|
WindowMessageResponse::JustRedraw
|
||||||
|
} else {
|
||||||
|
if self.state == State::Info {
|
||||||
|
self.state = State::List;
|
||||||
WindowMessageResponse::JustRedraw
|
WindowMessageResponse::JustRedraw
|
||||||
} else {
|
} else {
|
||||||
WindowMessageResponse::DoNothing
|
WindowMessageResponse::DoNothing
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => WindowMessageResponse::DoNothing,
|
_ => WindowMessageResponse::DoNothing,
|
||||||
}
|
}
|
||||||
@@ -138,7 +147,7 @@ impl WindowLike for FileExplorer {
|
|||||||
} else {
|
} else {
|
||||||
name.unwrap()
|
name.unwrap()
|
||||||
};
|
};
|
||||||
instructions.push(DrawInstructions::Text([5, start_y], vec!["nimbus-roman".to_string(), "shippori-mincho".to_string()], name, if is_selected { theme_info.top_text } else { theme_info.text }, if is_selected { theme_info.top } else { theme_info.background }, None, None));
|
instructions.push(DrawInstructions::Text([5, start_y + 4], vec!["nimbus-roman".to_string(), "shippori-mincho".to_string()], name, if is_selected { theme_info.top_text } else { theme_info.text }, if is_selected { theme_info.top } else { theme_info.background }, None, None));
|
||||||
start_y += HEIGHT;
|
start_y += HEIGHT;
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ use std::env;
|
|||||||
use linux::fb::Framebuffer;
|
use linux::fb::Framebuffer;
|
||||||
use termion::input::TermRead;
|
use termion::input::TermRead;
|
||||||
use termion::raw::IntoRawMode;
|
use termion::raw::IntoRawMode;
|
||||||
use termion::{ clear, cursor };
|
|
||||||
use termion::event::Key;
|
use termion::event::Key;
|
||||||
|
|
||||||
use ming_wm_lib::window_manager_types::KeyChar;
|
use ming_wm_lib::window_manager_types::KeyChar;
|
||||||
@@ -17,7 +16,11 @@ use ming_wm_lib::messages::*;
|
|||||||
use ming_wm::framebuffer::{ FramebufferWriter, FramebufferInfo };
|
use ming_wm::framebuffer::{ FramebufferWriter, FramebufferInfo };
|
||||||
use ming_wm::window_manager::WindowManager;
|
use ming_wm::window_manager::WindowManager;
|
||||||
|
|
||||||
//use Linear A for escape, backspace, enter
|
const CLEAR_ALL: &'static str = "\x1b[2J";
|
||||||
|
const HIDE_CURSOR: &'static str = "\x1b[?25l";
|
||||||
|
const SHOW_CURSOR: &'static str = "\x1b[?25h";
|
||||||
|
|
||||||
|
//use Linear A for escape, backspace, enter, arrow keys
|
||||||
//Linear A used only internally in onscreen keyboard: 𐘎 is alt, 𐘧 is switch board, 𐘾 is ctrl
|
//Linear A used only internally in onscreen keyboard: 𐘎 is alt, 𐘧 is switch board, 𐘾 is ctrl
|
||||||
fn key_to_char(key: Key) -> Option<KeyChar> {
|
fn key_to_char(key: Key) -> Option<KeyChar> {
|
||||||
match key {
|
match key {
|
||||||
@@ -27,6 +30,10 @@ fn key_to_char(key: Key) -> Option<KeyChar> {
|
|||||||
Key::Ctrl(c) => Some(KeyChar::Ctrl(c)),
|
Key::Ctrl(c) => Some(KeyChar::Ctrl(c)),
|
||||||
Key::Backspace => Some(KeyChar::Press('𐘁')),
|
Key::Backspace => Some(KeyChar::Press('𐘁')),
|
||||||
Key::Esc => Some(KeyChar::Press('𐘃')),
|
Key::Esc => Some(KeyChar::Press('𐘃')),
|
||||||
|
Key::Up => Some(KeyChar::Press('𐙘')),
|
||||||
|
Key::Down => Some(KeyChar::Press('𐘞')),
|
||||||
|
Key::Left => Some(KeyChar::Press('𐙣')),
|
||||||
|
Key::Right => Some(KeyChar::Press('𐙥')),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,9 +75,9 @@ fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) {
|
|||||||
|
|
||||||
let mut stdout = stdout().into_raw_mode().unwrap();
|
let mut stdout = stdout().into_raw_mode().unwrap();
|
||||||
|
|
||||||
write!(stdout, "{}", clear::All).unwrap();
|
write!(stdout, "{}", CLEAR_ALL).unwrap();
|
||||||
|
|
||||||
write!(stdout, "{}", cursor::Hide).unwrap();
|
write!(stdout, "{}", HIDE_CURSOR).unwrap();
|
||||||
|
|
||||||
stdout.flush().unwrap();
|
stdout.flush().unwrap();
|
||||||
|
|
||||||
@@ -109,10 +116,10 @@ fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) {
|
|||||||
let mut y: Option<usize> = None;
|
let mut y: Option<usize> = None;
|
||||||
for line in reader.lines() {
|
for line in reader.lines() {
|
||||||
let line = line.unwrap();
|
let line = line.unwrap();
|
||||||
if line.contains(&"ABS_X), value ") || line.contains(&"ABS_Y), value ") {
|
if line.contains("ABS_X), value ") || line.contains("ABS_Y), value ") {
|
||||||
let value: Vec<_> = line.split("), value ").collect();
|
let value: Vec<_> = line.split("), value ").collect();
|
||||||
let value = value[value.len() - 1].parse::<usize>().unwrap();
|
let value = value[value.len() - 1].parse::<usize>().unwrap();
|
||||||
if line.contains(&"ABS_X") {
|
if line.contains("ABS_X") {
|
||||||
x = Some(value);
|
x = Some(value);
|
||||||
} else {
|
} else {
|
||||||
y = Some(value);
|
y = Some(value);
|
||||||
@@ -147,12 +154,12 @@ fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) {
|
|||||||
ThreadMessage::KeyChar(kc) => wm.handle_message(WindowManagerMessage::KeyChar(kc.clone())),
|
ThreadMessage::KeyChar(kc) => wm.handle_message(WindowManagerMessage::KeyChar(kc.clone())),
|
||||||
ThreadMessage::Touch(x, y) => wm.handle_message(WindowManagerMessage::Touch(x, y)),
|
ThreadMessage::Touch(x, y) => wm.handle_message(WindowManagerMessage::Touch(x, y)),
|
||||||
ThreadMessage::Clear => {
|
ThreadMessage::Clear => {
|
||||||
write!(stdout, "{}", clear::All).unwrap();
|
write!(stdout, "{}", CLEAR_ALL).unwrap();
|
||||||
stdout.flush().unwrap();
|
stdout.flush().unwrap();
|
||||||
},
|
},
|
||||||
ThreadMessage::Exit => {
|
ThreadMessage::Exit => {
|
||||||
if !wm.locked {
|
if !wm.locked {
|
||||||
write!(stdout, "{}", cursor::Show).unwrap();
|
write!(stdout, "{}", SHOW_CURSOR).unwrap();
|
||||||
stdout.suspend_raw_mode().unwrap();
|
stdout.suspend_raw_mode().unwrap();
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use std::vec::Vec;
|
|||||||
use std::vec;
|
use std::vec;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fs::{ read_to_string, write };
|
use std::fs::{ read_to_string, write };
|
||||||
|
|
||||||
use ming_wm_lib::messages::{ WindowMessage, WindowMessageResponse, WindowManagerRequest, ShortcutType };
|
use ming_wm_lib::messages::{ WindowMessage, WindowMessageResponse, WindowManagerRequest, ShortcutType };
|
||||||
@@ -10,7 +11,7 @@ use ming_wm_lib::framebuffer_types::Dimensions;
|
|||||||
use ming_wm_lib::window_manager_types::{ DrawInstructions, WindowLike, WindowLikeType };
|
use ming_wm_lib::window_manager_types::{ DrawInstructions, WindowLike, WindowLikeType };
|
||||||
use ming_wm_lib::utils::{ calc_actual_lines, calc_new_cursor_pos, Substring };
|
use ming_wm_lib::utils::{ calc_actual_lines, calc_new_cursor_pos, Substring };
|
||||||
use ming_wm_lib::dirs::home;
|
use ming_wm_lib::dirs::home;
|
||||||
use ming_wm_lib::utils::path_autocomplete;
|
use ming_wm_lib::utils::{ get_rest_of_split, path_autocomplete };
|
||||||
use ming_wm_lib::ipc::listen;
|
use ming_wm_lib::ipc::listen;
|
||||||
|
|
||||||
const MONO_WIDTH: u8 = 10;
|
const MONO_WIDTH: u8 = 10;
|
||||||
@@ -94,7 +95,7 @@ impl WindowLike for Malvim {
|
|||||||
WindowMessage::KeyPress(key_press) => {
|
WindowMessage::KeyPress(key_press) => {
|
||||||
let mut changed = true;
|
let mut changed = true;
|
||||||
let mut new = false;
|
let mut new = false;
|
||||||
if key_press.key == '𐘃' { //escape key
|
if key_press.is_escape() {
|
||||||
self.mode = Mode::Normal;
|
self.mode = Mode::Normal;
|
||||||
self.state = State::None;
|
self.state = State::None;
|
||||||
changed = false;
|
changed = false;
|
||||||
@@ -113,7 +114,7 @@ impl WindowLike for Malvim {
|
|||||||
let current_file = &mut self.files[self.current_file_index];
|
let current_file = &mut self.files[self.current_file_index];
|
||||||
let current_length = current_file.content[current_file.line_pos].chars().count();
|
let current_length = current_file.content[current_file.line_pos].chars().count();
|
||||||
let line = ¤t_file.content[current_file.line_pos];
|
let line = ¤t_file.content[current_file.line_pos];
|
||||||
if key_press.key == '𐘂' { //the enter key
|
if key_press.is_enter() {
|
||||||
let mut line: Vec<char> = line.chars().collect();
|
let mut line: Vec<char> = line.chars().collect();
|
||||||
let (left, right) = line.split_at_mut(current_file.cursor_pos);
|
let (left, right) = line.split_at_mut(current_file.cursor_pos);
|
||||||
let left = left.into_iter().map(|c| c.to_string()).collect::<Vec<String>>().join("");
|
let left = left.into_iter().map(|c| c.to_string()).collect::<Vec<String>>().join("");
|
||||||
@@ -136,7 +137,7 @@ impl WindowLike for Malvim {
|
|||||||
current_file.content.insert(current_file.line_pos + 1, " ".repeat(spaces) + &right);
|
current_file.content.insert(current_file.line_pos + 1, " ".repeat(spaces) + &right);
|
||||||
current_file.line_pos += 1;
|
current_file.line_pos += 1;
|
||||||
current_file.cursor_pos = spaces;
|
current_file.cursor_pos = spaces;
|
||||||
} else if key_press.key == '𐘁' { //backspace
|
} else if key_press.is_backspace() {
|
||||||
if current_length > 0 && current_file.cursor_pos > 0 {
|
if current_length > 0 && current_file.cursor_pos > 0 {
|
||||||
current_file.content[current_file.line_pos] = line.remove(current_file.cursor_pos - 1, 1);
|
current_file.content[current_file.line_pos] = line.remove(current_file.cursor_pos - 1, 1);
|
||||||
current_file.cursor_pos -= 1;
|
current_file.cursor_pos -= 1;
|
||||||
@@ -150,7 +151,7 @@ impl WindowLike for Malvim {
|
|||||||
current_file.cursor_pos = old_previous_line_length;
|
current_file.cursor_pos = old_previous_line_length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if !key_press.is_arrow() { //arrow keys in insert mode is something i cannot support in good conscience
|
||||||
current_file.content[current_file.line_pos] = line.substring(0, current_file.cursor_pos).to_string() + &key_press.key.to_string() + line.substring(current_file.cursor_pos, line.chars().count());
|
current_file.content[current_file.line_pos] = line.substring(0, current_file.cursor_pos).to_string() + &key_press.key.to_string() + line.substring(current_file.cursor_pos, line.chars().count());
|
||||||
current_file.cursor_pos += 1;
|
current_file.cursor_pos += 1;
|
||||||
}
|
}
|
||||||
@@ -175,18 +176,23 @@ impl WindowLike for Malvim {
|
|||||||
}
|
}
|
||||||
let new_length = current_file.content[current_file.line_pos].chars().count();
|
let new_length = current_file.content[current_file.line_pos].chars().count();
|
||||||
current_file.cursor_pos = calc_new_cursor_pos(current_file.cursor_pos, new_length);
|
current_file.cursor_pos = calc_new_cursor_pos(current_file.cursor_pos, new_length);
|
||||||
} else if key_press.key == 'w' {
|
} else if key_press.key == 'w' || key_press.key == '$' {
|
||||||
let line = ¤t_file.content[current_file.line_pos];
|
let line = ¤t_file.content[current_file.line_pos];
|
||||||
let line_len = line.chars().count();
|
let line_len = line.chars().count();
|
||||||
if line_len > 0 && current_file.cursor_pos < line_len {
|
if line_len > 0 && current_file.cursor_pos < line_len {
|
||||||
//offset until space or eol
|
//offset until space or eol
|
||||||
let mut line_chars = line.chars().skip(current_file.cursor_pos).peekable();
|
let mut line_chars = line.chars().skip(current_file.cursor_pos).peekable();
|
||||||
let current_char = line_chars.peek().unwrap().clone();
|
//deref is Copy
|
||||||
let offset = line_chars.position(|c| if current_char == ' ' {
|
let current_char = *line_chars.peek().unwrap();
|
||||||
|
let offset = if key_press.key == 'w' {
|
||||||
|
line_chars.position(|c| if current_char == ' ' {
|
||||||
c != ' '
|
c != ' '
|
||||||
} else {
|
} else {
|
||||||
c == ' '
|
c == ' '
|
||||||
}).unwrap_or(line_len - current_file.cursor_pos);
|
}).unwrap_or(line_len - current_file.cursor_pos)
|
||||||
|
} else {
|
||||||
|
line_chars.count()
|
||||||
|
};
|
||||||
current_file.content[current_file.line_pos] = line.remove(current_file.cursor_pos, offset);
|
current_file.content[current_file.line_pos] = line.remove(current_file.cursor_pos, offset);
|
||||||
let new_length = current_file.content[current_file.line_pos].chars().count();
|
let new_length = current_file.content[current_file.line_pos].chars().count();
|
||||||
current_file.cursor_pos = calc_new_cursor_pos(current_file.cursor_pos, new_length);
|
current_file.cursor_pos = calc_new_cursor_pos(current_file.cursor_pos, new_length);
|
||||||
@@ -240,12 +246,14 @@ impl WindowLike for Malvim {
|
|||||||
if current_length == 1 {
|
if current_length == 1 {
|
||||||
current_file.cursor_pos = 0;
|
current_file.cursor_pos = 0;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
changed = false;
|
||||||
}
|
}
|
||||||
} else if key_press.key == 'h' {
|
} else if key_press.key == 'h' || key_press.is_left_arrow() {
|
||||||
current_file.cursor_pos = current_file.cursor_pos.checked_sub(self.maybe_num.unwrap_or(1)).unwrap_or(0);
|
current_file.cursor_pos = current_file.cursor_pos.checked_sub(self.maybe_num.unwrap_or(1)).unwrap_or(0);
|
||||||
changed = false;
|
changed = false;
|
||||||
} else if key_press.key == 'j' || key_press.key == 'k' {
|
} else if key_press.key == 'j' || key_press.is_down_arrow() || key_press.key == 'k' || key_press.is_up_arrow() {
|
||||||
if key_press.key == 'j' {
|
if key_press.key == 'j' || key_press.is_down_arrow() {
|
||||||
current_file.line_pos += self.maybe_num.unwrap_or(1);
|
current_file.line_pos += self.maybe_num.unwrap_or(1);
|
||||||
if current_file.line_pos >= current_file.content.len() {
|
if current_file.line_pos >= current_file.content.len() {
|
||||||
current_file.line_pos = current_file.content.len() - 1;
|
current_file.line_pos = current_file.content.len() - 1;
|
||||||
@@ -256,7 +264,7 @@ impl WindowLike for Malvim {
|
|||||||
let new_length = current_file.content[current_file.line_pos].chars().count();
|
let new_length = current_file.content[current_file.line_pos].chars().count();
|
||||||
current_file.cursor_pos = calc_new_cursor_pos(current_file.cursor_pos, new_length);
|
current_file.cursor_pos = calc_new_cursor_pos(current_file.cursor_pos, new_length);
|
||||||
changed = false;
|
changed = false;
|
||||||
} else if key_press.key == 'l' {
|
} else if key_press.key == 'l' || key_press.is_right_arrow() {
|
||||||
if current_length > 0 {
|
if current_length > 0 {
|
||||||
current_file.cursor_pos += self.maybe_num.unwrap_or(1);
|
current_file.cursor_pos += self.maybe_num.unwrap_or(1);
|
||||||
let line_len = current_file.content[current_file.line_pos].chars().count();
|
let line_len = current_file.content[current_file.line_pos].chars().count();
|
||||||
@@ -295,7 +303,88 @@ impl WindowLike for Malvim {
|
|||||||
} else if key_press.key == 'F' {
|
} else if key_press.key == 'F' {
|
||||||
self.state = State::BackFind;
|
self.state = State::BackFind;
|
||||||
changed = false;
|
changed = false;
|
||||||
} else if key_press.key.is_digit(10) {
|
} else if key_press.key == '%' {
|
||||||
|
let current_l = ¤t_file.content[current_file.line_pos];
|
||||||
|
if current_file.cursor_pos < current_l.len() {
|
||||||
|
let current_c = current_l.chars().nth(current_file.cursor_pos).unwrap();
|
||||||
|
let pairs = HashMap::from([
|
||||||
|
('(', (')', true)),
|
||||||
|
(')', ('(', false)),
|
||||||
|
('[', (']', true)),
|
||||||
|
(']', ('[', false)),
|
||||||
|
('"', ('"', true)), //could be either, really
|
||||||
|
('{', ('}', true)),
|
||||||
|
('}', ('{', false)),
|
||||||
|
('<', ('>', true)),
|
||||||
|
('>', ('<', false)),
|
||||||
|
//
|
||||||
|
]);
|
||||||
|
if let Some((corres, forwards)) = pairs.get(¤t_c) {
|
||||||
|
let mut count = 0;
|
||||||
|
let content_len = current_file.content.len();
|
||||||
|
let lines: Vec<&String> = if *forwards {
|
||||||
|
current_file.content.iter().skip(current_file.line_pos).collect()
|
||||||
|
} else {
|
||||||
|
current_file.content.iter().rev().skip(content_len - current_file.line_pos - 1).collect()
|
||||||
|
};
|
||||||
|
let end = if *forwards {
|
||||||
|
content_len - current_file.line_pos
|
||||||
|
} else {
|
||||||
|
current_file.line_pos + 1
|
||||||
|
};
|
||||||
|
'outer: for i in 0..end {
|
||||||
|
let line = if i == 0 {
|
||||||
|
let l = lines[i];
|
||||||
|
let l_len = l.len();
|
||||||
|
if *forwards {
|
||||||
|
if current_file.cursor_pos + 1 < l_len {
|
||||||
|
l.substring(current_file.cursor_pos + 1, l_len)
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
&l.substring(0, current_file.cursor_pos).chars().rev().collect::<String>()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if *forwards {
|
||||||
|
lines[i]
|
||||||
|
} else {
|
||||||
|
&lines[i].chars().rev().collect::<String>()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (c_i, c) in line.chars().enumerate() {
|
||||||
|
if c == current_c {
|
||||||
|
count += 1;
|
||||||
|
} else if &c == corres {
|
||||||
|
if count == 0 {
|
||||||
|
if *forwards {
|
||||||
|
current_file.line_pos += i;
|
||||||
|
} else {
|
||||||
|
current_file.line_pos -= i;
|
||||||
|
};
|
||||||
|
current_file.cursor_pos = if i == 0 {
|
||||||
|
if *forwards {
|
||||||
|
current_file.cursor_pos + c_i + 1
|
||||||
|
} else {
|
||||||
|
current_file.cursor_pos - c_i - 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if *forwards {
|
||||||
|
c_i
|
||||||
|
} else {
|
||||||
|
line.chars().count() - c_i - 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
count -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
changed = false;
|
||||||
|
} else if key_press.key.is_ascii_digit() {
|
||||||
self.maybe_num = Some(self.maybe_num.unwrap_or(0) * 10 + key_press.key.to_digit(10).unwrap() as usize);
|
self.maybe_num = Some(self.maybe_num.unwrap_or(0) * 10 + key_press.key.to_digit(10).unwrap() as usize);
|
||||||
numbered = true;
|
numbered = true;
|
||||||
changed = false;
|
changed = false;
|
||||||
@@ -309,7 +398,7 @@ impl WindowLike for Malvim {
|
|||||||
} else if self.mode == Mode::Command {
|
} else if self.mode == Mode::Command {
|
||||||
self.bottom_message = None;
|
self.bottom_message = None;
|
||||||
let command = self.command.clone().unwrap_or("".to_string());
|
let command = self.command.clone().unwrap_or("".to_string());
|
||||||
if key_press.key == '𐘂' { //the enter key
|
if key_press.is_enter() {
|
||||||
new = self.process_command();
|
new = self.process_command();
|
||||||
self.command = None;
|
self.command = None;
|
||||||
self.mode = Mode::Normal;
|
self.mode = Mode::Normal;
|
||||||
@@ -330,7 +419,7 @@ impl WindowLike for Malvim {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if key_press.key == '𐘁' { //backspace
|
} else if key_press.is_backspace() {
|
||||||
if command.len() > 0 {
|
if command.len() > 0 {
|
||||||
self.command = Some(command[..command.len() - 1].to_string());
|
self.command = Some(command[..command.len() - 1].to_string());
|
||||||
}
|
}
|
||||||
@@ -401,7 +490,7 @@ impl WindowLike for Malvim {
|
|||||||
let mut used_width = 0;
|
let mut used_width = 0;
|
||||||
for file_index in 0..self.files.len() {
|
for file_index in 0..self.files.len() {
|
||||||
let file_info = &self.files[file_index];
|
let file_info = &self.files[file_index];
|
||||||
let future_used_width = used_width + 4 + (file_info.name.len() + if file_info.changed { 2 } else { 0 }) * MONO_WIDTH as usize;
|
let future_used_width = used_width + 4 + (file_info.name.len() + if file_info.changed { 2 } else { 0 }) * MONO_WIDTH as usize + 15;
|
||||||
//just cut off when too many file tabs open to fit
|
//just cut off when too many file tabs open to fit
|
||||||
if future_used_width > self.dimensions[0] {
|
if future_used_width > self.dimensions[0] {
|
||||||
break;
|
break;
|
||||||
@@ -455,12 +544,11 @@ impl WindowLike for Malvim {
|
|||||||
//bottom blue band stuff
|
//bottom blue band stuff
|
||||||
//write mode
|
//write mode
|
||||||
instructions.push(DrawInstructions::Text([0, self.dimensions[1] - BAND_HEIGHT * 2 + 2], vec!["nimbus-romono".to_string()], self.mode.to_string(), theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH)));
|
instructions.push(DrawInstructions::Text([0, self.dimensions[1] - BAND_HEIGHT * 2 + 2], vec!["nimbus-romono".to_string()], self.mode.to_string(), theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH)));
|
||||||
let file_status;
|
let file_status = if self.files.len() > 0 {
|
||||||
if self.files.len() > 0 {
|
self.files[self.current_file_index].name.clone()
|
||||||
file_status = self.files[self.current_file_index].name.clone();
|
|
||||||
} else {
|
} else {
|
||||||
file_status = "No file open".to_string();
|
"No file open".to_string()
|
||||||
}
|
};
|
||||||
instructions.push(DrawInstructions::Text([self.dimensions[0] - file_status.len() * (MONO_WIDTH as usize), self.dimensions[1] - BAND_HEIGHT * 2 + 2], vec!["nimbus-romono".to_string()], file_status, theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH)));
|
instructions.push(DrawInstructions::Text([self.dimensions[0] - file_status.len() * (MONO_WIDTH as usize), self.dimensions[1] - BAND_HEIGHT * 2 + 2], vec!["nimbus-romono".to_string()], file_status, theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH)));
|
||||||
//write command or bottom message
|
//write command or bottom message
|
||||||
if self.mode == Mode::Command {
|
if self.mode == Mode::Command {
|
||||||
@@ -593,12 +681,40 @@ impl Malvim {
|
|||||||
} else if first.starts_with("/") {
|
} else if first.starts_with("/") {
|
||||||
let current_file = &mut self.files[self.current_file_index];
|
let current_file = &mut self.files[self.current_file_index];
|
||||||
if current_file.content.len() > 0 {
|
if current_file.content.len() > 0 {
|
||||||
let found_line_no = current_file.content.iter().skip(current_file.line_pos + 1).position(|line| {
|
let p1 = if arg == "" {
|
||||||
line.contains(&first[1..])
|
String::new()
|
||||||
});
|
} else {
|
||||||
if let Some(found_line_no) = found_line_no {
|
" ".to_string() + arg
|
||||||
current_file.line_pos = found_line_no + current_file.line_pos + 1;
|
};
|
||||||
current_file.cursor_pos = 0;
|
let rest = get_rest_of_split(&mut parts, Some(" "));
|
||||||
|
let rest = if rest == "" {
|
||||||
|
String::new()
|
||||||
|
} else {
|
||||||
|
" ".to_string() + &rest
|
||||||
|
};
|
||||||
|
let query = first[1..].to_string() + &p1 + &rest;
|
||||||
|
let mut lines = current_file.content.iter().skip(current_file.line_pos);
|
||||||
|
for i in 0..(current_file.content.len() - current_file.line_pos) {
|
||||||
|
let line = if i == 0 {
|
||||||
|
let l = lines.next().unwrap();
|
||||||
|
let l_len = l.len();
|
||||||
|
if (current_file.cursor_pos + 1) < l_len {
|
||||||
|
l.substring(current_file.cursor_pos + 1, l_len)
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lines.next().unwrap()
|
||||||
|
};
|
||||||
|
if let Some(found_index) = line.to_string().find_substring(&query) {
|
||||||
|
current_file.line_pos += i;
|
||||||
|
current_file.cursor_pos = if i == 0 {
|
||||||
|
current_file.cursor_pos + found_index + 1
|
||||||
|
} else {
|
||||||
|
found_index
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if first == "x" || first == "w" || first == "write" || first == "q" || first == "quit" {
|
} else if first == "x" || first == "w" || first == "write" || first == "q" || first == "quit" {
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ impl WindowLike for Minesweeper {
|
|||||||
self.random_chars = String::new();
|
self.random_chars = String::new();
|
||||||
self.state = State::BeforePlaying;
|
self.state = State::BeforePlaying;
|
||||||
} else {
|
} else {
|
||||||
|
//since must be u8, the Linear A (enter, backspace, etc) stuff won't do anything
|
||||||
if u8::try_from(key_press.key).is_ok() {
|
if u8::try_from(key_press.key).is_ok() {
|
||||||
self.random_chars.push(key_press.key);
|
self.random_chars.push(key_press.key);
|
||||||
}
|
}
|
||||||
@@ -64,15 +65,15 @@ impl WindowLike for Minesweeper {
|
|||||||
self.first_char = '\0';
|
self.first_char = '\0';
|
||||||
WindowMessageResponse::DoNothing
|
WindowMessageResponse::DoNothing
|
||||||
} else if self.first_char == '\0' {
|
} else if self.first_char == '\0' {
|
||||||
if HEX_CHARS.iter().find(|c| c == &&key_press.key).is_some() {
|
if HEX_CHARS.iter().any(|c| c == &key_press.key) {
|
||||||
self.first_char = key_press.key;
|
self.first_char = key_press.key;
|
||||||
}
|
}
|
||||||
WindowMessageResponse::DoNothing
|
WindowMessageResponse::DoNothing
|
||||||
} else if HEX_CHARS.iter().find(|c| c == &&key_press.key).is_some() {
|
} else if HEX_CHARS.iter().any(|c| c == &key_press.key) {
|
||||||
let u = hex_to_u8(self.first_char, key_press.key) as usize;
|
let u = hex_to_u8(self.first_char, key_press.key) as usize;
|
||||||
let y = u / 16;
|
let y = u / 16;
|
||||||
let x = u % 16;
|
let x = u % 16;
|
||||||
if HEX_CHARS.iter().find(|c| c == &&key_press.key).is_some() {
|
if HEX_CHARS.iter().any(|c| c == &key_press.key) {
|
||||||
if self.state == State::BeforePlaying {
|
if self.state == State::BeforePlaying {
|
||||||
loop {
|
loop {
|
||||||
self.new_tiles();
|
self.new_tiles();
|
||||||
|
|||||||
@@ -104,13 +104,13 @@ impl WindowLike for Terminal {
|
|||||||
WindowMessage::KeyPress(key_press) => {
|
WindowMessage::KeyPress(key_press) => {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
Mode::Input => {
|
Mode::Input => {
|
||||||
if key_press.key == '𐘁' { //backspace
|
if key_press.is_backspace() {
|
||||||
if self.current_input.len() > 0 {
|
if self.current_input.len() > 0 {
|
||||||
self.current_input = self.current_input.remove_last();
|
self.current_input = self.current_input.remove_last();
|
||||||
} else {
|
} else {
|
||||||
return WindowMessageResponse::DoNothing;
|
return WindowMessageResponse::DoNothing;
|
||||||
}
|
}
|
||||||
} else if key_press.key == '𐘂' { //the enter key
|
} else if key_press.is_enter() {
|
||||||
self.lines.push("$ ".to_string() + &self.current_input);
|
self.lines.push("$ ".to_string() + &self.current_input);
|
||||||
self.history.push(self.current_input.clone());
|
self.history.push(self.current_input.clone());
|
||||||
self.history_index = None;
|
self.history_index = None;
|
||||||
@@ -127,7 +127,11 @@ impl WindowLike for Terminal {
|
|||||||
return WindowMessageResponse::DoNothing;
|
return WindowMessageResponse::DoNothing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if key_press.is_up_arrow() {
|
||||||
|
self.prev();
|
||||||
|
} else if key_press.is_down_arrow() {
|
||||||
|
self.next();
|
||||||
|
} else if key_press.is_regular() {
|
||||||
self.current_input += &key_press.key.to_string();
|
self.current_input += &key_press.key.to_string();
|
||||||
}
|
}
|
||||||
self.calc_actual_lines();
|
self.calc_actual_lines();
|
||||||
@@ -175,19 +179,16 @@ impl WindowLike for Terminal {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Mode::Stdin => {
|
Mode::Stdin => {
|
||||||
if key_press.key == '𐘃' {
|
if key_press.is_escape() {
|
||||||
//esc
|
|
||||||
self.mode = Mode::Running;
|
self.mode = Mode::Running;
|
||||||
} else if key_press.key == '𐘂' {
|
} else if key_press.is_enter() {
|
||||||
//enter
|
|
||||||
let _ = self.pty_in_tx.as_mut().unwrap().send(self.current_stdin_input.clone());
|
let _ = self.pty_in_tx.as_mut().unwrap().send(self.current_stdin_input.clone());
|
||||||
self.mode = Mode::Running;
|
self.mode = Mode::Running;
|
||||||
let pcl_len = self.process_current_line.len();
|
let pcl_len = self.process_current_line.len();
|
||||||
self.lines.push(strip_ansi_escape_codes(String::from_utf8(self.process_current_line.clone()).unwrap_or("?".repeat(pcl_len))) + &self.current_stdin_input);
|
self.lines.push(strip_ansi_escape_codes(String::from_utf8(self.process_current_line.clone()).unwrap_or("?".repeat(pcl_len))) + &self.current_stdin_input);
|
||||||
self.current_stdin_input = String::new();
|
self.current_stdin_input = String::new();
|
||||||
self.process_current_line = Vec::new();
|
self.process_current_line = Vec::new();
|
||||||
} else if key_press.key == '𐘁' {
|
} else if key_press.is_backspace() {
|
||||||
//backspace
|
|
||||||
if self.current_stdin_input.len() > 0 {
|
if self.current_stdin_input.len() > 0 {
|
||||||
self.current_stdin_input = self.current_stdin_input.remove_last();
|
self.current_stdin_input = self.current_stdin_input.remove_last();
|
||||||
} else {
|
} else {
|
||||||
@@ -210,24 +211,12 @@ impl WindowLike for Terminal {
|
|||||||
} else if self.mode == Mode::Input && (key_press.key == 'p' || key_press.key == 'n') {
|
} else if self.mode == Mode::Input && (key_press.key == 'p' || key_press.key == 'n') {
|
||||||
//only the last command is saved unlike other terminals. good enough for me
|
//only the last command is saved unlike other terminals. good enough for me
|
||||||
if key_press.key == 'p' && self.history.len() > 0 {
|
if key_press.key == 'p' && self.history.len() > 0 {
|
||||||
if let Some(history_index) = self.history_index {
|
|
||||||
if history_index > 0 {
|
self.prev();
|
||||||
self.history_index = Some(history_index - 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.history_index = Some(self.history.len() - 1);
|
|
||||||
}
|
|
||||||
self.current_input = self.history[self.history_index.unwrap()].clone();
|
|
||||||
self.calc_actual_lines();
|
self.calc_actual_lines();
|
||||||
WindowMessageResponse::JustRedraw
|
WindowMessageResponse::JustRedraw
|
||||||
} else if key_press.key == 'n' {
|
} else if key_press.key == 'n' {
|
||||||
if self.history_index.is_none() || self.history_index.unwrap() == self.history.len() - 1 {
|
self.next();
|
||||||
self.history_index = None;
|
|
||||||
self.current_input = String::new();
|
|
||||||
} else {
|
|
||||||
self.history_index = Some(self.history_index.unwrap() + 1);
|
|
||||||
self.current_input = self.history[self.history_index.unwrap()].clone();
|
|
||||||
}
|
|
||||||
self.calc_actual_lines();
|
self.calc_actual_lines();
|
||||||
WindowMessageResponse::JustRedraw
|
WindowMessageResponse::JustRedraw
|
||||||
} else {
|
} else {
|
||||||
@@ -300,6 +289,27 @@ impl Terminal {
|
|||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn prev(&mut self) {
|
||||||
|
if let Some(history_index) = self.history_index {
|
||||||
|
if history_index > 0 {
|
||||||
|
self.history_index = Some(history_index - 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.history_index = Some(self.history.len() - 1);
|
||||||
|
}
|
||||||
|
self.current_input = self.history[self.history_index.unwrap()].clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next(&mut self) {
|
||||||
|
if self.history_index.is_none() || self.history_index.unwrap() == self.history.len() - 1 {
|
||||||
|
self.history_index = None;
|
||||||
|
self.current_input = String::new();
|
||||||
|
} else {
|
||||||
|
self.history_index = Some(self.history_index.unwrap() + 1);
|
||||||
|
self.current_input = self.history[self.history_index.unwrap()].clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_max_lines(&self) -> usize {
|
fn get_max_lines(&self) -> usize {
|
||||||
(self.dimensions[1] - PADDING * 2 - LINE_HEIGHT) / LINE_HEIGHT
|
(self.dimensions[1] - PADDING * 2 - LINE_HEIGHT) / LINE_HEIGHT
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,12 +28,12 @@ impl WindowLike for Help {
|
|||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
};
|
};
|
||||||
self.paragraph = Some(Box::new(Paragraph::new("help".to_string(), [2, 22], [self.dimensions[0] - 4, self.dimensions[1] - 24], "Press the 'h' and 'l' keys to read the different help pages".to_string() + &first_content, ())));
|
self.paragraph = Some(Box::new(Paragraph::new("help".to_string(), [2, 22], [self.dimensions[0] - 4, self.dimensions[1] - 24], "Press the 'h' and 'l' keys (or the left and right arrow keys) to read the different help pages".to_string() + &first_content, ())));
|
||||||
WindowMessageResponse::JustRedraw
|
WindowMessageResponse::JustRedraw
|
||||||
},
|
},
|
||||||
WindowMessage::KeyPress(key_press) => {
|
WindowMessage::KeyPress(key_press) => {
|
||||||
if key_press.key == 'h' || key_press.key == 'l' {
|
if key_press.key == 'h' || key_press.is_left_arrow() || key_press.key == 'l' || key_press.is_right_arrow() {
|
||||||
if key_press.key == 'h' {
|
if key_press.key == 'h' || key_press.is_left_arrow() {
|
||||||
if self.file_index == 0 {
|
if self.file_index == 0 {
|
||||||
self.file_index = self.files.len() - 1;
|
self.file_index = self.files.len() - 1;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ impl WindowLike for LockScreen {
|
|||||||
WindowMessageResponse::JustRedraw
|
WindowMessageResponse::JustRedraw
|
||||||
},
|
},
|
||||||
WindowMessage::KeyPress(key_press) => {
|
WindowMessage::KeyPress(key_press) => {
|
||||||
if key_press.key == '𐘂' { //the enter key
|
if key_press.is_enter() {
|
||||||
//check password
|
//check password
|
||||||
let mut hasher = Blake2b512::new();
|
let mut hasher = Blake2b512::new();
|
||||||
hasher.update((self.input_password.clone() + "salt?sorrycryptographers").as_bytes());
|
hasher.update((self.input_password.clone() + "salt?sorrycryptographers").as_bytes());
|
||||||
@@ -34,15 +34,17 @@ impl WindowLike for LockScreen {
|
|||||||
self.input_password = String::new();
|
self.input_password = String::new();
|
||||||
WindowMessageResponse::JustRedraw
|
WindowMessageResponse::JustRedraw
|
||||||
}
|
}
|
||||||
} else if key_press.key == '𐘁' { //backspace
|
} else if key_press.is_backspace() {
|
||||||
let p_len = self.input_password.len();
|
let p_len = self.input_password.len();
|
||||||
if p_len != 0 {
|
if p_len != 0 {
|
||||||
self.input_password = self.input_password[..p_len - 1].to_string();
|
self.input_password = self.input_password[..p_len - 1].to_string();
|
||||||
}
|
}
|
||||||
WindowMessageResponse::JustRedraw
|
WindowMessageResponse::JustRedraw
|
||||||
} else {
|
} else if key_press.is_regular() {
|
||||||
self.input_password += &key_press.key.to_string();
|
self.input_password += &key_press.key.to_string();
|
||||||
WindowMessageResponse::JustRedraw
|
WindowMessageResponse::JustRedraw
|
||||||
|
} else {
|
||||||
|
WindowMessageResponse::DoNothing
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => WindowMessageResponse::DoNothing,
|
_ => WindowMessageResponse::DoNothing,
|
||||||
|
|||||||
@@ -42,10 +42,10 @@ impl WindowLike for StartMenu {
|
|||||||
},
|
},
|
||||||
WindowMessage::KeyPress(key_press) => {
|
WindowMessage::KeyPress(key_press) => {
|
||||||
//up and down
|
//up and down
|
||||||
if key_press.key == 'k' || key_press.key == 'j' {
|
if key_press.key == 'j' || key_press.is_down_arrow() || key_press.key == 'k' || key_press.is_up_arrow() {
|
||||||
let old_focus_index = self.get_focus_index().unwrap();
|
let old_focus_index = self.get_focus_index().unwrap();
|
||||||
self.components[old_focus_index].handle_message(WindowMessage::Unfocus);
|
self.components[old_focus_index].handle_message(WindowMessage::Unfocus);
|
||||||
let current_focus_index = if key_press.key == 'j' {
|
let current_focus_index = if key_press.key == 'j' || key_press.is_down_arrow() {
|
||||||
if old_focus_index + 1 == self.components.len() {
|
if old_focus_index + 1 == self.components.len() {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
@@ -61,7 +61,7 @@ impl WindowLike for StartMenu {
|
|||||||
self.current_focus = self.components[current_focus_index].name().to_string();
|
self.current_focus = self.components[current_focus_index].name().to_string();
|
||||||
self.components[current_focus_index].handle_message(WindowMessage::Focus);
|
self.components[current_focus_index].handle_message(WindowMessage::Focus);
|
||||||
WindowMessageResponse::JustRedraw
|
WindowMessageResponse::JustRedraw
|
||||||
} else if key_press.key == '𐘂' { //the enter key
|
} else if key_press.is_enter() {
|
||||||
let focus_index = self.get_focus_index();
|
let focus_index = self.get_focus_index();
|
||||||
if let Some(focus_index) = focus_index {
|
if let Some(focus_index) = focus_index {
|
||||||
let r = self.components[focus_index].handle_message(WindowMessage::FocusClick);
|
let r = self.components[focus_index].handle_message(WindowMessage::FocusClick);
|
||||||
@@ -108,14 +108,19 @@ impl WindowLike for StartMenu {
|
|||||||
DrawInstructions::Rect([self.dimensions[0] - 1, 0], [1, self.dimensions[1]], theme_info.border_right_bottom),
|
DrawInstructions::Rect([self.dimensions[0] - 1, 0], [1, self.dimensions[1]], theme_info.border_right_bottom),
|
||||||
//background
|
//background
|
||||||
DrawInstructions::Rect([0, 1], [self.dimensions[0] - 1, self.dimensions[1] - 1], theme_info.background),
|
DrawInstructions::Rect([0, 1], [self.dimensions[0] - 1, self.dimensions[1] - 1], theme_info.background),
|
||||||
//mingde logo
|
//ming-wm logo
|
||||||
DrawInstructions::Bmp([2, 2], exe_dir(Some("ming_bmps/mingde.bmp")).to_string_lossy().to_string(), false),
|
DrawInstructions::Bmp([2, 2], exe_dir(Some("ming_bmps/ming-wm.bmp")).to_string_lossy().to_string(), true),
|
||||||
//I truly don't know why, it should be - 44 but - 30 seems to work better :shrug:
|
//I truly don't know why, it should be - 44 but - 30 seems to work better :shrug:
|
||||||
DrawInstructions::Gradient([2, 42], [40, self.dimensions[1] - 30], [255, 201, 14], [225, 219, 77], 15),
|
DrawInstructions::Gradient([2, 42], [40, self.dimensions[1] - 30], [255, 201, 14], [225, 219, 100], 15), //[225, 219, 77]
|
||||||
];
|
];
|
||||||
for component in &self.components {
|
let max_per_page = CATEGORIES.len();
|
||||||
|
let current_focus = self.get_focus_index().unwrap();
|
||||||
|
for (index, component) in self.components.iter().enumerate() {
|
||||||
|
//supports multiple pages of window options per category
|
||||||
|
if (index >= max_per_page && current_focus >= max_per_page) || (index < max_per_page && current_focus < max_per_page) {
|
||||||
instructions.extend(component.draw(theme_info));
|
instructions.extend(component.draw(theme_info));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
instructions
|
instructions
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,9 +157,13 @@ impl StartMenu {
|
|||||||
];
|
];
|
||||||
//add window buttons
|
//add window buttons
|
||||||
if let Some(to_add) = self.executable_windows.get(&("ming".to_string() + name)) {
|
if let Some(to_add) = self.executable_windows.get(&("ming".to_string() + name)) {
|
||||||
for a in 0..to_add.len() {
|
let max_per_page = CATEGORIES.len();
|
||||||
|
//starts at 1 because of back button
|
||||||
|
for a in 1..=to_add.len() {
|
||||||
|
let ta = &to_add[a - 1];
|
||||||
|
//the modulo is for multiple pages for windows per category
|
||||||
self.components.push(Box::new(HighlightButton::new(
|
self.components.push(Box::new(HighlightButton::new(
|
||||||
to_add[a].1.to_string(), [42, (a + 1) * self.y_each], [self.dimensions[0] - 42 - 1, self.y_each], to_add[a].0.to_string(), StartMenuMessage::WindowClick(to_add[a].1.clone()), StartMenuMessage::ChangeAcknowledge, false
|
ta.1.to_string(), [42, (a % max_per_page) * self.y_each], [self.dimensions[0] - 42 - 1, self.y_each], ta.0.to_string(), StartMenuMessage::WindowClick(ta.1.clone()), StartMenuMessage::ChangeAcknowledge, false
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -183,8 +192,7 @@ impl StartMenu {
|
|||||||
pub fn add_category_components(&mut self) {
|
pub fn add_category_components(&mut self) {
|
||||||
self.current_focus = "About".to_string();
|
self.current_focus = "About".to_string();
|
||||||
self.components = Vec::new();
|
self.components = Vec::new();
|
||||||
for c in 0..CATEGORIES.len() {
|
for (c, name) in CATEGORIES.iter().enumerate() {
|
||||||
let name = CATEGORIES[c];
|
|
||||||
self.components.push(Box::new(HighlightButton::new(
|
self.components.push(Box::new(HighlightButton::new(
|
||||||
name.to_string(), [42, self.y_each * c + 1], [self.dimensions[0] - 42 - 1, self.y_each], name.to_string(), StartMenuMessage::CategoryClick(name), StartMenuMessage::ChangeAcknowledge, c == 0
|
name.to_string(), [42, self.y_each * c + 1], [self.dimensions[0] - 42 - 1, self.y_each], name.to_string(), StartMenuMessage::CategoryClick(name), StartMenuMessage::ChangeAcknowledge, c == 0
|
||||||
)));
|
)));
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ impl FramebufferWriter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.rotate_buffer = Some(output_array);
|
self.rotate_buffer = Some(output_array);
|
||||||
&self.rotate_buffer.as_ref().unwrap()
|
self.rotate_buffer.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_buffer(&mut self) {
|
pub fn save_buffer(&mut self) {
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ impl WindowManager {
|
|||||||
pub fn add_window_like(&mut self, mut window_like: Box<dyn WindowLike>, top_left: Point, dimensions: Option<Dimensions>) {
|
pub fn add_window_like(&mut self, mut window_like: Box<dyn WindowLike>, top_left: Point, dimensions: Option<Dimensions>) {
|
||||||
let subtype = window_like.subtype();
|
let subtype = window_like.subtype();
|
||||||
let dimensions = dimensions.unwrap_or(window_like.ideal_dimensions(self.dimensions));
|
let dimensions = dimensions.unwrap_or(window_like.ideal_dimensions(self.dimensions));
|
||||||
self.id_count = self.id_count + 1;
|
self.id_count += 1;
|
||||||
let id = self.id_count;
|
let id = self.id_count;
|
||||||
window_like.handle_message(WindowMessage::Init(dimensions));
|
window_like.handle_message(WindowMessage::Init(dimensions));
|
||||||
let dimensions = if subtype == WindowLikeType::Window { [dimensions[0], dimensions[1] + WINDOW_TOP_HEIGHT] } else { dimensions };
|
let dimensions = if subtype == WindowLikeType::Window { [dimensions[0], dimensions[1] + WINDOW_TOP_HEIGHT] } else { dimensions };
|
||||||
@@ -154,7 +154,7 @@ impl WindowManager {
|
|||||||
file.read_to_string(&mut contents).unwrap();
|
file.read_to_string(&mut contents).unwrap();
|
||||||
let lines: Vec<&str> = contents.split("\n").collect();
|
let lines: Vec<&str> = contents.split("\n").collect();
|
||||||
if lines.len() > self.current_workspace.into() {
|
if lines.len() > self.current_workspace.into() {
|
||||||
self.theme = Themes::from_str(lines[self.current_workspace as usize]).unwrap_or(Default::default());
|
self.theme = Themes::from_str(lines[self.current_workspace as usize]).unwrap_or_default();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -667,8 +667,7 @@ impl WindowManager {
|
|||||||
});
|
});
|
||||||
//these are needed to decide when to snapshot
|
//these are needed to decide when to snapshot
|
||||||
let max_index = if redraw_ids.len() > 0 { redraw_ids.len() } else { maybe_length } - 1;
|
let max_index = if redraw_ids.len() > 0 { redraw_ids.len() } else { maybe_length } - 1;
|
||||||
let mut w_index = 0;
|
for (w_index, window_info) in redraw_windows.enumerate() {
|
||||||
for window_info in redraw_windows {
|
|
||||||
let window_dimensions = if window_info.fullscreen {
|
let window_dimensions = if window_info.fullscreen {
|
||||||
[self.dimensions[0], self.dimensions[1] - TASKBAR_HEIGHT - INDICATOR_HEIGHT]
|
[self.dimensions[0], self.dimensions[1] - TASKBAR_HEIGHT - INDICATOR_HEIGHT]
|
||||||
} else {
|
} else {
|
||||||
@@ -746,7 +745,6 @@ impl WindowManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.writer.borrow_mut().draw_buffer(window_info.top_left, window_dimensions[1], window_dimensions[0] * bytes_per_pixel, &window_writer.get_buffer());
|
self.writer.borrow_mut().draw_buffer(window_info.top_left, window_dimensions[1], window_dimensions[0] * bytes_per_pixel, &window_writer.get_buffer());
|
||||||
w_index += 1;
|
|
||||||
}
|
}
|
||||||
//could probably figure out a way to do borrow() when self.rotate is false but does it matter?
|
//could probably figure out a way to do borrow() when self.rotate is false but does it matter?
|
||||||
let mut writer_borrow = self.writer.borrow_mut();
|
let mut writer_borrow = self.writer.borrow_mut();
|
||||||
|
|||||||