Skip to content

Commit

Permalink
Add toy feature for displaying a clock in the console
Browse files Browse the repository at this point in the history
  • Loading branch information
johnlng committed Nov 8, 2024
1 parent 47da5a5 commit 76852d3
Show file tree
Hide file tree
Showing 11 changed files with 392 additions and 8 deletions.
3 changes: 2 additions & 1 deletion slickcmd/res/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#define IDC_CHK_RUN_ON_START 1006
#define IDC_CHK_RUN_ON_STARTUP 1006
#define IDC_SYSLINK1 1007
#define IDC_CHK_SHOW_CLOCK 1008
#define IDC_STATIC -1

// Next default values for new objects
Expand All @@ -32,7 +33,7 @@
#define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 133
#define _APS_NEXT_COMMAND_VALUE 32771
#define _APS_NEXT_CONTROL_VALUE 1008
#define _APS_NEXT_CONTROL_VALUE 1009
#define _APS_NEXT_SYMED_VALUE 110
#endif
#endif
3 changes: 2 additions & 1 deletion slickcmd/res/slickcmd.rc
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ BEGIN
CONTROL "",IDC_SPIN2,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,49,21,11,14
CONTROL "&Path auto-complete for 'cd'",IDC_CHK_CD_COMPLETION,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,49,102,10
CONTROL "&Run on Start Up",IDC_CHK_RUN_ON_STARTUP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,70,67,10
CONTROL "&Run on Start Up",IDC_CHK_RUN_ON_STARTUP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,66,67,10
CONTROL "Console &Clock",IDC_CHK_SHOW_CLOCK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,83,60,10
END


Expand Down
Binary file modified slickcmd/res/slickcmd.res
Binary file not shown.
213 changes: 213 additions & 0 deletions slickcmd/src/clock_win.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
use crate::global::GLOBAL;
use crate::win_man::WinMan;
use crate::wt_focus_man::WtFocusMan;
use slickcmd_common::consts::{WM_SYSTEM_MOVESIZEEND, WM_SYSTEM_MOVESIZESTART, WM_WT_FOCUS_CHANGE};
use slickcmd_common::font_info::FontInfo;
use slickcmd_common::winproc::{wndproc, WinProc};
use slickcmd_common::{logd, win32};
use std::ffi::c_void;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::Relaxed;
use windows::Win32::Foundation::*;
use windows::Win32::Graphics::Gdi::*;
use windows::Win32::UI::WindowsAndMessaging::*;

static WC_REGISTERED: AtomicBool = AtomicBool::new(false);

pub struct ClockWin {
hwnd: HWND,
hwnd_term: HWND,

hfont: HFONT,

last_console_bounds: RECT,

width: i32,
height: i32,

is_wt: bool,
}

impl ClockWin {
pub fn new(hwnd_term: HWND) -> ClockWin {
ClockWin {
hwnd: HWND::default(),
hwnd_term,
hfont: HFONT::default(),
last_console_bounds: RECT::default(),
width: 0,
height: 0,
is_wt: hwnd_term.0 as usize == WtFocusMan::hwnd_wt(),
}
}

fn register_class(window_class: &str) -> bool {
let wsz_class = win32::wsz_from_str(window_class);

let wc = WNDCLASSEXW {
cbSize: size_of::<WNDCLASSEXW>() as u32,
hInstance: GLOBAL.hinstance(),
hCursor: win32::load_cursor(IDC_ARROW),
hbrBackground: HBRUSH((COLOR_WINDOW.0 + 1) as *mut c_void),
lpszClassName: win32::pwsz(&wsz_class),
lpfnWndProc: Some(wndproc::<Self>),
..Default::default()
};

let atom = win32::register_class_ex(&wc);
if atom == 0 {
return false;
}
true
}

pub fn create(&mut self, fi: FontInfo, cell_size: (i32, i32)) {
let window_class = "slck_cmd_clock";
if !WC_REGISTERED.load(Relaxed) {
if !Self::register_class(&window_class) {
debug_assert!(false);
}
WC_REGISTERED.store(true, Relaxed);
}

let mut lf = LOGFONTW::default();
lf.lfWidth = fi.width;
lf.lfHeight = fi.height;
lf.lfPitchAndFamily = fi.pitch_and_family;
lf.lfCharSet = DEFAULT_CHARSET;

let wsz_facename = win32::wsz_from_str(&fi.name);
lf.lfFaceName[..wsz_facename.len()].copy_from_slice(wsz_facename.as_slice());

self.hfont = win32::create_font_indirect(&lf);

//
self.width = cell_size.0 * "23:45:59".len() as i32;
self.height = cell_size.1;
let style = if self.is_wt { WS_POPUP } else { WS_CHILD };
let hwnd = win32::create_window_ex(
WINDOW_EX_STYLE::default(),
&window_class,
"",
style,
0,
0,
self.width,
self.height,
self.hwnd_term,
HMENU::default(),
GLOBAL.hinstance(),
Some(self as *const _ as *const c_void),
);
self.hwnd = hwnd;
if self.is_wt {
WtFocusMan::add_wt_listener_hwnd(self.hwnd);
} else {
let style = win32::get_window_long(self.hwnd_term, GWL_STYLE);
let style = WINDOW_STYLE(style as u32);
if !style.contains(WS_CLIPCHILDREN) {
let style = style | WS_CLIPCHILDREN;
win32::set_window_long(self.hwnd_term, GWL_STYLE, style.0 as i32);
}
}

self.on_timer();
win32::set_timer(self.hwnd, 1, 1000, None);
}

pub fn destroy(&mut self) {
if self.is_wt {
WtFocusMan::remove_wt_listener_hwnd(self.hwnd);
}
if self.hwnd.is_invalid() {
logd!("??");
return;
}
win32::destroy_window(self.hwnd);
win32::delete_object(self.hfont.into());
self.hwnd = HWND::default();
self.hfont = HFONT::default();
}

fn on_timer(&mut self) {
let console_bounds = WinMan::get_console_bounds(self.hwnd_term);
let hwnd = self.hwnd;
if self.last_console_bounds != console_bounds {
self.last_console_bounds = console_bounds;
let mut pt = POINT {
x: console_bounds.right - self.width,
y: console_bounds.top,
};
if self.is_wt {
win32::client_to_screen(self.hwnd_term, &mut pt);
}

win32::move_window(hwnd, pt.x, pt.y, self.width, self.height, false);
win32::show_window(hwnd, SW_SHOWNOACTIVATE);

if !self.is_wt {
win32::invalidate_rect(self.hwnd_term, None, true);
win32::update_window(self.hwnd_term);
}
}

win32::invalidate_rect(hwnd, None, false);
win32::update_window(hwnd);
}

fn on_paint(&mut self) {
let mut ps = PAINTSTRUCT::default();
win32::begin_paint(self.hwnd, &mut ps);
let hfont_old = win32::select_object(ps.hdc, self.hfont.into());

let bg_color = win32::rgb(0, 0, 168);
let hbr = win32::create_solid_brush(bg_color);
win32::fill_rect(ps.hdc, &ps.rcPaint, hbr);
win32::delete_object(hbr.into());

let st = win32::get_local_time();
let s_time = format!("{:02}:{:02}:{:02}", st.wHour, st.wMinute, st.wSecond);
win32::set_bk_color(ps.hdc, bg_color);
win32::set_text_color(ps.hdc, win32::rgb(240, 240, 240));

let mut rc = RECT {
left: 0,
top: 0,
right: self.width,
bottom: self.height,
};
win32::draw_text(
ps.hdc,
&s_time,
&mut rc,
DT_SINGLELINE | DT_CENTER | DT_VCENTER,
);

win32::select_object(ps.hdc, hfont_old);
win32::end_paint(self.hwnd, &ps);
}
}

impl WinProc for ClockWin {
fn wndproc(&mut self, window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
match message {
WM_TIMER => {
self.on_timer();
return LRESULT(0);
}
WM_PAINT => {
self.on_paint();
return LRESULT(0);
}
WM_SYSTEM_MOVESIZESTART => {
win32::show_window(self.hwnd, SW_HIDE);
}
WM_SYSTEM_MOVESIZEEND | WM_WT_FOCUS_CHANGE => {
self.last_console_bounds = RECT::default();
self.on_timer();
}
_ => {}
}
unsafe { DefWindowProcW(window, message, wparam, lparam) }
}
}
19 changes: 19 additions & 0 deletions slickcmd/src/console.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use windows::Win32::System::Threading::*;
use windows::Win32::UI::Input::KeyboardAndMouse::*;
use windows::Win32::UI::WindowsAndMessaging::*;
use crate::app::App;
use crate::clock_win::ClockWin;
use crate::win_man::WinMan;

#[derive(Default)]
Expand Down Expand Up @@ -48,6 +49,7 @@ pub struct Console {
update_cur_dir_on_key_up: bool,
manual_cd_completing: bool,

clock_win: Option<Box<ClockWin>>,
}

#[derive(Default)]
Expand Down Expand Up @@ -207,13 +209,30 @@ impl Console {
self.update_cur_dir();
}

if GLOBAL.options.show_clock() {
let clock_win = ClockWin::new(self.hwnd_term);

let bounds = self.get_console_bounds();
let size = (bounds.right - bounds.left, bounds.bottom - bounds.top);
let dim_info = self.read_dimension_info(size);

let fi = self.get_font_info(&dim_info);

let mut clock_win = Box::new(clock_win);
clock_win.create(fi, (dim_info.cell_width, dim_info.cell_height));
self.clock_win = Some(clock_win);
}
}

pub fn on_deactivate(&mut self) {
logd!("@ CONSOLE DEACTIVATE");
if self.showing_ac_list {
self.hide_ac_list();
}
if let Some(clock_win) = &mut self.clock_win {
clock_win.destroy();
self.clock_win = None;
}
win32::unregister_hotkey(self.hwnd_msg, 1);
self.command_hist.save();
}
Expand Down
1 change: 1 addition & 0 deletions slickcmd/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ pub mod win_man;
pub mod app_state;
pub mod wt_focus_man;
pub mod console_man;
pub mod clock_win;
11 changes: 10 additions & 1 deletion slickcmd/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub struct Options {
max_recent_dirs: Cell<u32>,
cd_completion: Cell<bool>,
run_on_startup: Cell<bool>,

show_clock: Cell<bool>,
}

impl Options {
Expand All @@ -23,13 +23,15 @@ impl Options {
ini.write("General", "max_recent_dirs", self.max_recent_dirs());
ini.write("General", "cd_completion", self.cd_completion());
ini.write("General", "run_on_startup", self.run_on_startup());
ini.write("General", "show_clock", self.show_clock());
}

pub fn init(&self) {
let ini = Ini::new(Some(&Self::get_ini_path()));
self.set_max_recent_dirs(ini.read_or("General", "max_recent_dirs", 15));
self.set_cd_completion(ini.read_or("General", "cd_completion", true));
self.set_run_on_startup(ini.read_or("General", "run_on_startup", true));
self.set_show_clock(ini.read_or("General", "show_clock", false));
}

pub fn max_recent_dirs(&self) -> u32 {
Expand All @@ -56,4 +58,11 @@ impl Options {
self.run_on_startup.set(value);
}

pub fn show_clock(&self) -> bool {
self.show_clock.get()
}

pub fn set_show_clock(&self, value: bool) {
self.show_clock.set(value);
}
}
10 changes: 6 additions & 4 deletions slickcmd/src/options_dlg.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use crate::startup_link::StartupLink;
use slickcmd_common::consts::{
IDC_CHK_CD_COMPLETION, IDC_CHK_RUN_ON_STARTUP, IDC_MAX_RECENT_DIRS, IDC_MAX_RECENT_DIRS_SPIN,
IDD_OPTIONS,
};
use slickcmd_common::consts::{IDC_CHK_CD_COMPLETION, IDC_CHK_RUN_ON_STARTUP, IDC_CHK_SHOW_CLOCK, IDC_MAX_RECENT_DIRS, IDC_MAX_RECENT_DIRS_SPIN, IDD_OPTIONS};
use slickcmd_common::dlg::{dlg_proc, Dlg};
use slickcmd_common::{dlg, utils, win32};
use windows::Win32::Foundation::*;
Expand All @@ -17,6 +14,7 @@ pub struct OptionsDlg {
hwnd_max_recent_dirs: HWND,
hwnd_chk_cd_completion: HWND,
hwnd_chk_run_on_startup: HWND,
hwnd_chk_show_clock: HWND,
}

impl OptionsDlg {
Expand Down Expand Up @@ -48,13 +46,15 @@ impl OptionsDlg {

self.hwnd_chk_cd_completion = win32::get_dlg_item(self.hwnd, IDC_CHK_CD_COMPLETION);
self.hwnd_chk_run_on_startup = win32::get_dlg_item(self.hwnd, IDC_CHK_RUN_ON_STARTUP);
self.hwnd_chk_show_clock = win32::get_dlg_item(self.hwnd, IDC_CHK_SHOW_CLOCK);

let options = &GLOBAL.options;
let text = &format!("{}", options.max_recent_dirs());
win32::set_window_text(self.hwnd_max_recent_dirs, text);

self.set_check(self.hwnd_chk_cd_completion, options.cd_completion());
self.set_check(self.hwnd_chk_run_on_startup, options.run_on_startup());
self.set_check(self.hwnd_chk_show_clock, options.show_clock());

1
}
Expand All @@ -78,11 +78,13 @@ impl OptionsDlg {

let enable_cd_completion = self.get_check(self.hwnd_chk_cd_completion);
let run_on_startup = self.get_check(self.hwnd_chk_run_on_startup);
let show_clock = self.get_check(self.hwnd_chk_show_clock);

let options = &GLOBAL.options;
options.set_max_recent_dirs(max_recent_dirs);
options.set_cd_completion(enable_cd_completion);
options.set_run_on_startup(run_on_startup);
options.set_show_clock(show_clock);
options.save();

//
Expand Down
Loading

0 comments on commit 76852d3

Please sign in to comment.