From ea3f447af1870c3636ffd88f24fe1a70a45e4459 Mon Sep 17 00:00:00 2001 From: Hans Dijkema Date: Thu, 20 Nov 2025 16:59:14 +0100 Subject: [PATCH] Working YellowNotes on Windows. --- CMakeLists.txt | 3 +- color.png | Bin 0 -> 3779 bytes color.svg | 17 + delete.png | Bin 0 -> 3283 bytes delete.svg | 10 + gtk-imports.h | 454 +++++++++++++++++++-- gtkloader.cpp | 2 + hide.png | Bin 0 -> 26647 bytes hide.svg | 27 ++ main.cpp | 5 +- plus.png | Bin 0 -> 7459 bytes plus.svg | 4 + tr.cpp | 94 +++++ tr.h | 31 ++ yellownotes.cpp | 1024 +++++++++++++++++++++++++++++++++++++++++++---- yellownotes.h | 59 ++- 16 files changed, 1607 insertions(+), 123 deletions(-) create mode 100644 color.png create mode 100644 color.svg create mode 100644 delete.png create mode 100644 delete.svg create mode 100644 hide.png create mode 100644 hide.svg create mode 100644 plus.png create mode 100644 plus.svg create mode 100644 tr.cpp create mode 100644 tr.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 74da535..fa0b7bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,8 @@ add_executable(yellownotes main.cpp gtk-imports.h gtkloader.h gtkloader.cpp gtk-imports.c - yellownotes.h yellownotes.cpp) + yellownotes.h yellownotes.cpp + tr.h tr.cpp) include(GNUInstallDirs) install(TARGETS yellownotes diff --git a/color.png b/color.png new file mode 100644 index 0000000000000000000000000000000000000000..734c72818c1b76162c1eab3f55e83085b125da90 GIT binary patch literal 3779 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 + + Font-Color + + + + + + + + + + + + + + \ No newline at end of file diff --git a/delete.png b/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..d9105a62a4698212fd01adb012939d07e03fbe48 GIT binary patch literal 3283 zcmeHKX;jnK62D0xu^0kTWKjqj5jT`2vIzk!L8T&SQ9)2akwhAnV334GOvFkQlqi)N zRs|lQk5v#Xp!`qSH4p&}Pzd}*MHG{O0b~=J_RH%#ujjSz`}=Uu+%q%h&OI~poBO+0 z4!G}8S6i(H08n?`OZgT6gmQ}j%g{=3>}(-bDZXOtJ<0?C*YMjyw1gF&Rx0%(T)ZPZ z!>AFglV<|~i^bX=6iR0XoMZ%U4?9asm)Wld0PF8c*>#AWA(dPZW(Gz<6LM7-O)vf4 zyDkN5zu&)H&1Rb}LTA>z%BJd-O6LYrb4cI7bjuFs3IWf&lags19DD_5UERm)U!l73 za>$~t>OIGumv#9z8D019yiL%0Ue&Y6?pWi;7b_~|Oxe4Pv3b`yOqATYv`(s!GCN{A z&hMcT@8usZ#yn4^G^TL6IW!cVv#~1kjLS!)Om$J?k=`S7l3}Rb&D2XQ5aQCf3kpM& zBHUGRXY4v*f{KIM!eMG${*>8EJ+CDC*yw=C81dx3n$_~R+TN5{pR5j*RugiNa)8#x?*YEtc%>7~AyZ%)N^ZT`YzwH#6R{Ya9JTX9@FarALyh7@bz1D`*Wr0Vv1&8j!n*RQwT^9tC{26;@B*SBa^ee5q#-)a zlq3%#3$v1}0Di&(mNV=^+N=Ayegu5qh3yCb<_HX9^N9tYSUR_-ig2oJlME1tXBidmK#cU)l|ReNNGWtsw^hOWrwpvDMjtV zkcK47$K?ZvIt}*z{L;mgL&;Ua=Y?OM`O;GG-!R;j+S?6LAl()jhe z=o@oSg$bi4Bul%J6Q*YE9B-Gaz^-I*oKXv-pSUeWFqAj+Q-UMug~|D(4dDFXr~ZYg zluC?mOp!rT|3J$Mj>AHaUw|bm{h}}c7!_;&X}SN<3s$LMGAgFDR+U~f_p#LcYIS9@ z^4RG;cF~3F^1e(83G{l$UM;dR){v}x`Y_&H+|4Z!W!{|Fz}cfL^0nc@vhv`sBG*X>7tRMG7FW+$NaD`!!+|V>{sW6{R}hT0026xSr(K6}?Qi&66V>!0i}Xdob-r zeFz!4d2j#$D2)?P`=jGk+WkvlBWG{#-+`Y~-2dF0oe(Qo&fWu>3Nv5ABJj`DChrG{u^5SO_maV*EhKrE?IAVK&HpUi>7V~8z0UO~43E7DN%P=+7=^V!(bdc#A_q5Of+8?CUzmTJF1J52*aIHmDB9HeH zx&?Vi1N)-kPknC6+k>(jve*Q2lv-K%gCkpoVIRyEb#2&b=kVdJ&l}tptj6DL7Js2q z?3wV<)C^Vou&d`bqTb=`_qn3|b!qNDg<3M6^5adI%|DD?eE)99ue(E~BK@8g$}DMp zOi|{D-`iWT+nl-5w=+Omw1^!!pYK4o-0)Yh`_I(>*Sh@Q_*XC3|C}M+-MGrg3zM_w zBQ>m=)?b^LKXetL+bkiA2Q7QGk|!ku`c~2Js&k$t{fO9;t-DfZOSxiMvU$hv>KJaO zXHl&^iG?K#8&^S}^SxPzse?Nw%~ocEC-zM>rNGdToq7`sDQAN=oZLIF5RY*kv)d_r zK|j|EsUZ*S>*4ftP>HR=1``zSTegjj-fSGkUm zsanxSQ0lZf{jzmLF+!BHyi12vAzFTRE4f<=Md8D>7%McPRAF7kOSi+i9Bv>LX}v%0 zTJxKn+Q(D+&jLq|_|wO1w@hsQH@fh5l3nJq%qd%PDxhq0o^9na1iP^17t8qlcU>5# zMN=e6XV9`lO^%c-cCaO8IrbW*u}qaL!_S zYKg->@I``#-IdUmzD#`hl37X+PG!7%ex{dx#s NxVpGgO1}2L_$wjztpfl6 literal 0 HcmV?d00001 diff --git a/delete.svg b/delete.svg new file mode 100644 index 0000000..fc2ebd9 --- /dev/null +++ b/delete.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/gtk-imports.h b/gtk-imports.h index cbe3a26..0282eb8 100644 --- a/gtk-imports.h +++ b/gtk-imports.h @@ -44,12 +44,30 @@ typedef GtkMenuShell GtkMenu; typedef void GtkMenuItem; typedef void GdkEvent; typedef void GtkTextBuffer; +typedef void GtkTextView; typedef void GtkTextTagTable; typedef void GtkContainer; typedef void GtkLabel; typedef void GtkHeaderBar; typedef void GdkWindow; typedef void GdkDevice; +typedef void GtkImage; +typedef void GdkPixbuf; +typedef void GError; +typedef void GtkStyleContext; +typedef void GtkCssProvider; +typedef void GtkStyleProvider; +typedef void GtkWidgetPath; +typedef void GtkAdjustment; +typedef void GtkFrame; +typedef void GtkEventBox; +typedef void GdkCursor; +typedef void GdkDisplay; +typedef void GtkEntry; +typedef void GtkDialog; +typedef void GTimer; +typedef void GtkComboBoxText; +typedef void GtkComboBox; typedef int gboolean; typedef int gint; @@ -63,11 +81,14 @@ typedef unsigned long long guint64; typedef float gfloat; typedef double gdouble; typedef char gint8; +typedef unsigned char guint8; typedef short gint16; - +typedef unsigned short guint16; +typedef size_t gssize; typedef enum { - GTK_WINDOW_TOPLEVEL = 0 + GTK_WINDOW_TOPLEVEL = 0, + GTK_WINDOW_POPUP = 1 } GtkWindowType; typedef enum { @@ -172,36 +193,56 @@ typedef struct _GtkTextIter { typedef enum { - GDK_DELETE, - GDK_MOTION_NOTIFY, - GDK_BUTTON_PRESS, - GDK_BUTTON_RELEASE, - GDK_KEY_PRESS, - GDK_KEY_RELEASE, - GDK_ENTER_NOTIFY, - GDK_LEAVE_NOTIFY, - GDK_FOCUS_CHANGE, - GDK_PROXIMITY_IN, - GDK_PROXIMITY_OUT, - GDK_DRAG_ENTER, - GDK_DRAG_LEAVE, - GDK_DRAG_MOTION, - GDK_DROP_START, - GDK_SCROLL, - GDK_GRAB_BROKEN, - GDK_TOUCH_BEGIN, - GDK_TOUCH_UPDATE, - GDK_TOUCH_END, - GDK_TOUCH_CANCEL, - GDK_TOUCHPAD_SWIPE, - GDK_TOUCHPAD_PINCH, - GDK_PAD_BUTTON_PRESS, - GDK_PAD_BUTTON_RELEASE, - GDK_PAD_RING, - GDK_PAD_STRIP, - GDK_PAD_GROUP_MODE, - GDK_TOUCHPAD_HOLD, - GDK_PAD_DIAL, + GDK_NOTHING = -1, + GDK_DELETE = 0, + GDK_DESTROY = 1, + GDK_EXPOSE = 2, + GDK_MOTION_NOTIFY = 3, + GDK_BUTTON_PRESS = 4, + GDK_2BUTTON_PRESS = 5, + GDK_DOUBLE_BUTTON_PRESS = GDK_2BUTTON_PRESS, + GDK_3BUTTON_PRESS = 6, + GDK_TRIPLE_BUTTON_PRESS = GDK_3BUTTON_PRESS, + GDK_BUTTON_RELEASE = 7, + GDK_KEY_PRESS = 8, + GDK_KEY_RELEASE = 9, + GDK_ENTER_NOTIFY = 10, + GDK_LEAVE_NOTIFY = 11, + GDK_FOCUS_CHANGE = 12, + GDK_CONFIGURE = 13, + GDK_MAP = 14, + GDK_UNMAP = 15, + GDK_PROPERTY_NOTIFY = 16, + GDK_SELECTION_CLEAR = 17, + GDK_SELECTION_REQUEST = 18, + GDK_SELECTION_NOTIFY = 19, + GDK_PROXIMITY_IN = 20, + GDK_PROXIMITY_OUT = 21, + GDK_DRAG_ENTER = 22, + GDK_DRAG_LEAVE = 23, + GDK_DRAG_MOTION = 24, + GDK_DRAG_STATUS = 25, + GDK_DROP_START = 26, + GDK_DROP_FINISHED = 27, + GDK_CLIENT_EVENT = 28, + GDK_VISIBILITY_NOTIFY = 29, + GDK_SCROLL = 31, + GDK_WINDOW_STATE = 32, + GDK_SETTING = 33, + GDK_OWNER_CHANGE = 34, + GDK_GRAB_BROKEN = 35, + GDK_DAMAGE = 36, + GDK_TOUCH_BEGIN = 37, + GDK_TOUCH_UPDATE = 38, + GDK_TOUCH_END = 39, + GDK_TOUCH_CANCEL = 40, + GDK_TOUCHPAD_SWIPE = 41, + GDK_TOUCHPAD_PINCH = 42, + GDK_PAD_BUTTON_PRESS = 43, + GDK_PAD_BUTTON_RELEASE = 44, + GDK_PAD_RING = 45, + GDK_PAD_STRIP = 46, + GDK_PAD_GROUP_MODE = 47, GDK_EVENT_LAST /* helper variable for decls */ } GdkEventType; @@ -235,8 +276,22 @@ typedef struct _GdkEventMotion gdouble x_root, y_root; } GdkEventMotion; +typedef struct _GdkEventKey +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + guint state; + guint keyval; + gint length; + gchar *string; + guint16 hardware_keycode; + guint8 group; + guint is_modifier : 1; +} GdkEventKey; - +#define GDK_KEY_Escape 65307 typedef enum { @@ -268,14 +323,260 @@ typedef enum GDK_ALL_EVENTS_MASK = 0x3FFFFFE } GdkEventMask; +typedef enum +{ + GTK_STATE_FLAG_NORMAL = 0, + GTK_STATE_FLAG_ACTIVE = 1 << 0, + GTK_STATE_FLAG_PRELIGHT = 1 << 1, + GTK_STATE_FLAG_SELECTED = 1 << 2, + GTK_STATE_FLAG_INSENSITIVE = 1 << 3, + GTK_STATE_FLAG_INCONSISTENT = 1 << 4, + GTK_STATE_FLAG_FOCUSED = 1 << 5, + GTK_STATE_FLAG_BACKDROP = 1 << 6, + GTK_STATE_FLAG_DIR_LTR = 1 << 7, + GTK_STATE_FLAG_DIR_RTL = 1 << 8, + GTK_STATE_FLAG_LINK = 1 << 9, + GTK_STATE_FLAG_VISITED = 1 << 10, + GTK_STATE_FLAG_CHECKED = 1 << 11, + GTK_STATE_FLAG_DROP_ACTIVE = 1 << 12 +} GtkStateFlags; + + +typedef void (* GtkMenuPositionFunc) ( + GtkMenu* menu, + gint* x, + gint* y, + gboolean* push_in, + gpointer user_data + ); + +typedef struct _GdkRGBA +{ + gdouble red; + gdouble green; + gdouble blue; + gdouble alpha; +} GdkRGBA; + +typedef struct _GtkRequisition +{ + gint width; + gint height; +} GtkRequisition; + +typedef enum { + GTK_STYLE_CONTEXT_PRINT_NONE = 0, + GTK_STYLE_CONTEXT_PRINT_RECURSE = 1 << 0, + GTK_STYLE_CONTEXT_PRINT_SHOW_STYLE = 1 << 1 +} GtkStyleContextPrintFlags; + +typedef enum +{ + GTK_WRAP_NONE, + GTK_WRAP_CHAR, + GTK_WRAP_WORD, + GTK_WRAP_WORD_CHAR +} GtkWrapMode; + +typedef enum +{ + GTK_SHADOW_NONE, + GTK_SHADOW_IN, + GTK_SHADOW_OUT, + GTK_SHADOW_ETCHED_IN, + GTK_SHADOW_ETCHED_OUT +} GtkShadowType; + +typedef enum +{ + GDK_X_CURSOR = 0, + GDK_ARROW = 2, + GDK_BASED_ARROW_DOWN = 4, + GDK_BASED_ARROW_UP = 6, + GDK_BOAT = 8, + GDK_BOGOSITY = 10, + GDK_BOTTOM_LEFT_CORNER = 12, + GDK_BOTTOM_RIGHT_CORNER = 14, + GDK_BOTTOM_SIDE = 16, + GDK_BOTTOM_TEE = 18, + GDK_BOX_SPIRAL = 20, + GDK_CENTER_PTR = 22, + GDK_CIRCLE = 24, + GDK_CLOCK = 26, + GDK_COFFEE_MUG = 28, + GDK_CROSS = 30, + GDK_CROSS_REVERSE = 32, + GDK_CROSSHAIR = 34, + GDK_DIAMOND_CROSS = 36, + GDK_DOT = 38, + GDK_DOTBOX = 40, + GDK_DOUBLE_ARROW = 42, + GDK_DRAFT_LARGE = 44, + GDK_DRAFT_SMALL = 46, + GDK_DRAPED_BOX = 48, + GDK_EXCHANGE = 50, + GDK_FLEUR = 52, + GDK_GOBBLER = 54, + GDK_GUMBY = 56, + GDK_HAND1 = 58, + GDK_HAND2 = 60, + GDK_HEART = 62, + GDK_ICON = 64, + GDK_IRON_CROSS = 66, + GDK_LEFT_PTR = 68, + GDK_LEFT_SIDE = 70, + GDK_LEFT_TEE = 72, + GDK_LEFTBUTTON = 74, + GDK_LL_ANGLE = 76, + GDK_LR_ANGLE = 78, + GDK_MAN = 80, + GDK_MIDDLEBUTTON = 82, + GDK_MOUSE = 84, + GDK_PENCIL = 86, + GDK_PIRATE = 88, + GDK_PLUS = 90, + GDK_QUESTION_ARROW = 92, + GDK_RIGHT_PTR = 94, + GDK_RIGHT_SIDE = 96, + GDK_RIGHT_TEE = 98, + GDK_RIGHTBUTTON = 100, + GDK_RTL_LOGO = 102, + GDK_SAILBOAT = 104, + GDK_SB_DOWN_ARROW = 106, + GDK_SB_H_DOUBLE_ARROW = 108, + GDK_SB_LEFT_ARROW = 110, + GDK_SB_RIGHT_ARROW = 112, + GDK_SB_UP_ARROW = 114, + GDK_SB_V_DOUBLE_ARROW = 116, + GDK_SHUTTLE = 118, + GDK_SIZING = 120, + GDK_SPIDER = 122, + GDK_SPRAYCAN = 124, + GDK_STAR = 126, + GDK_TARGET = 128, + GDK_TCROSS = 130, + GDK_TOP_LEFT_ARROW = 132, + GDK_TOP_LEFT_CORNER = 134, + GDK_TOP_RIGHT_CORNER = 136, + GDK_TOP_SIDE = 138, + GDK_TOP_TEE = 140, + GDK_TREK = 142, + GDK_UL_ANGLE = 144, + GDK_UMBRELLA = 146, + GDK_UR_ANGLE = 148, + GDK_WATCH = 150, + GDK_XTERM = 152, + GDK_LAST_CURSOR, + GDK_BLANK_CURSOR = -2, + GDK_CURSOR_IS_PIXMAP = -1 +} GdkCursorType; + +typedef enum +{ + GTK_ALIGN_FILL, + GTK_ALIGN_START, + GTK_ALIGN_END, + GTK_ALIGN_CENTER, + GTK_ALIGN_BASELINE +} GtkAlign; + +typedef enum +{ + GTK_DIALOG_MODAL = 1 << 0, + GTK_DIALOG_DESTROY_WITH_PARENT = 1 << 1, + GTK_DIALOG_USE_HEADER_BAR = 1 << 2 +} GtkDialogFlags; + +typedef enum +{ + GTK_MESSAGE_INFO, + GTK_MESSAGE_WARNING, + GTK_MESSAGE_QUESTION, + GTK_MESSAGE_ERROR, + GTK_MESSAGE_OTHER +} GtkMessageType; + +typedef enum +{ + GTK_BUTTONS_NONE, + GTK_BUTTONS_OK, + GTK_BUTTONS_CLOSE, + GTK_BUTTONS_CANCEL, + GTK_BUTTONS_YES_NO, + GTK_BUTTONS_OK_CANCEL +} GtkButtonsType; + +typedef enum +{ + GTK_RESPONSE_NONE = -1, + GTK_RESPONSE_REJECT = -2, + GTK_RESPONSE_ACCEPT = -3, + GTK_RESPONSE_DELETE_EVENT = -4, + GTK_RESPONSE_OK = -5, + GTK_RESPONSE_CANCEL = -6, + GTK_RESPONSE_CLOSE = -7, + GTK_RESPONSE_YES = -8, + GTK_RESPONSE_NO = -9, + GTK_RESPONSE_APPLY = -10, + GTK_RESPONSE_HELP = -11 +} GtkResponseType; + +typedef struct _GdkEventFocus +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + gint16 in; +} GdkEventFocus; + +typedef gboolean (*GSourceFunc) (gpointer user_data); + +typedef enum +{ + GDK_WINDOW_TYPE_HINT_NORMAL, + GDK_WINDOW_TYPE_HINT_DIALOG, + GDK_WINDOW_TYPE_HINT_MENU, /* Torn off menu */ + GDK_WINDOW_TYPE_HINT_TOOLBAR, + GDK_WINDOW_TYPE_HINT_SPLASHSCREEN, + GDK_WINDOW_TYPE_HINT_UTILITY, + GDK_WINDOW_TYPE_HINT_DOCK, + GDK_WINDOW_TYPE_HINT_DESKTOP, + GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU, /* A drop down menu (from a menubar) */ + GDK_WINDOW_TYPE_HINT_POPUP_MENU, /* A popup menu (from right-click) */ + GDK_WINDOW_TYPE_HINT_TOOLTIP, + GDK_WINDOW_TYPE_HINT_NOTIFICATION, + GDK_WINDOW_TYPE_HINT_COMBO, + GDK_WINDOW_TYPE_HINT_DND +} GdkWindowTypeHint; + +typedef enum +{ + GDK_VISIBILITY_UNOBSCURED, + GDK_VISIBILITY_PARTIAL, + GDK_VISIBILITY_FULLY_OBSCURED +} GdkVisibilityState; + +typedef struct _GdkEventVisibility +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkVisibilityState state; +} GdkEventVisibility; #define G_TYPE_FUNDAMENTAL_SHIFT (2) #define G_TYPE_MAKE_FUNDAMENTAL(x) ((GType) ((x) << G_TYPE_FUNDAMENTAL_SHIFT)) #define G_TYPE_INT G_TYPE_MAKE_FUNDAMENTAL (6) +#define GTK_STYLE_PROVIDER_PRIORITY_USER 800 #endif +// GLib +DECL(GTimer*, g_timeout_add, (guint interval, GSourceFunc func, gpointer data)); + +// Gtk Application / Window / Widget + DECL(GtkApplication *, gtk_application_new, (const char *name, GApplicationFlags flags)) DECL(int, g_application_run, (GApplication* application, int argc, char** argv)) @@ -287,47 +588,105 @@ DECL(void, gtk_window_set_decorated, (GtkWindow* window, gboolean setting )) DECL(void, gtk_widget_show_all, (GtkWindow *window)) DECL(void, gtk_widget_hide, (GtkWidget* widget )) +DECL(void, gtk_widget_show, (GtkWidget* widget)) +DECL(gboolean, gtk_widget_grab_focus, ( GtkWidget* widget )) DECL(GtkWidget*, gtk_event_box_new, (void)) +DECL(void, gtk_event_box_set_visible_window, (GtkEventBox* event_box, gboolean visible_window )) DECL(void, gtk_window_get_size, (GtkWindow *win, int *width, int *height)) DECL(void, gtk_window_resize, (GtkWindow* window, gint width, gint height)) DECL(void, gtk_window_set_default_size, (GtkWindow *window, gint width, gint height)) DECL(void, gtk_window_get_position, (GtkWindow* window, gint* root_x, gint* root_y)) DECL(void, gtk_window_move, (GtkWindow* window, gint x, gint y)) +DECL(void, gtk_window_present, (GtkWindow* window)) +DECL(void, gtk_window_set_type_hint, (GtkWindow* window, GdkWindowTypeHint hint)) +DECL(void, gtk_window_set_skip_taskbar_hint, (GtkWindow* window, gboolean setting)) +DECL(void, gtk_window_set_skip_pager_hint, (GtkWindow* window, gboolean setting)) +DECL(void, gtk_widget_set_can_focus, (GtkWidget* widget, gboolean can_focus )) +DECL(void, gtk_window_set_transient_for, (GtkWindow* window, GtkWindow* parent )) +DECL(GType, gtk_window_get_type, (void)) +DECL(GObject*, g_object_new, (GType object_type, const gchar* first_property_name, ...)) + +DECL(void, gtk_widget_set_size_request, (GtkWidget* widget, int width, int height )) +DECL(void, gtk_widget_get_preferred_size, (GtkWidget* widget, GtkRequisition* minimum_size, GtkRequisition* natural_size)) +DECL(void, gtk_widget_get_allocation, ( GtkWidget* widget, GtkAllocation* allocation )) DECL(void, gtk_window_set_resizable, (GtkWindow* window, gboolean resizable)) DECL(GdkWindow *, gtk_widget_get_window, (GtkWidget *w)); +DECL(GdkWindow*, gdk_window_get_effective_toplevel, (GdkWindow* window)) +DECL(void, gdk_window_set_override_redirect, (GdkWindow* window, gboolean override_redirect)) +DECL(GtkWidget*, gtk_scrolled_window_new, (GtkAdjustment* hadjustment, GtkAdjustment* vadjustment)) DECL(gboolean, gtk_window_get_decorated, (GtkWindow* window)) DECL(void, gdk_window_set_events, (GdkWindow* window, GdkEventMask event_mask )) +DECL(GdkEventMask, gdk_window_get_events, (GdkWindow* window )) DECL(void, gtk_window_set_title, (GtkWindow* window, const gchar* title)) DECL(const gchar*, gtk_window_get_title, (GtkWindow* window)) DECL(void, gtk_widget_destroy, (GtkWidget* widget)) DECL(void, gtk_container_add, (GtkContainer* container, GtkWidget* widget)) +DECL(void, gtk_container_remove, (GtkContainer* container, GtkWidget* widget)) + DECL(gboolean, gtk_widget_is_visible, (GtkWidget* widget)) DECL(GtkWidget*, gtk_label_new, (const char* str)) DECL(void, gtk_label_set_ellipsize, (GtkLabel* label, PangoEllipsizeMode mode)) DECL(void, gtk_label_set_label, (GtkLabel* label, const gchar* str)) DECL(const gchar*, gtk_label_get_text, (GtkLabel* label)) +DECL(GtkWidget*, gtk_entry_new, (void)) +DECL(void, gtk_entry_set_text, (GtkEntry* entry, const gchar* text )) +DECL(const gchar*, gtk_entry_get_text, (GtkEntry* entry)) + +DECL(GtkWidget*, gtk_separator_new, ( GtkOrientation orientation )) + +DECL(GtkWidget*, gtk_frame_new, ( const gchar* label )) +DECL(void, gtk_frame_set_shadow_type, (GtkFrame* frame, GtkShadowType type )) DECL(GtkWidget*, gtk_box_new, (GtkOrientation orientation, gint spacing )) +DECL(void, gtk_widget_set_vexpand, (GtkWidget* widget, gboolean expand )) +DECL(void, gtk_widget_set_hexpand, (GtkWidget* widget, gboolean expand )) +DECL(void, gtk_widget_set_halign, (GtkWidget* widget, GtkAlign align )) +DECL(void, gtk_widget_set_valign, (GtkWidget* widget, GtkAlign align )) + +DECL(gboolean, gtk_widget_translate_coordinates, ( GtkWidget* src_widget, GtkWidget* dest_widget, gint src_x, gint src_y, gint* dest_x, gint* dest_y)) DECL(void, gtk_main, (void)) DECL(void, gtk_main_quit, (void)) DECL(unsigned long, g_signal_connect_data, (GObject *obj, const char *signal, GCallback c_handler, gpointer data, GClosureNotify destroy_data, GConnectFlags connect_flags)) +// Messages +DECL(GtkWidget*, gtk_message_dialog_new, (GtkWindow* parent, GtkDialogFlags flags, GtkMessageType type, GtkButtonsType buttons, const gchar* message_format, ...)) +DECL(gint, gtk_dialog_run, (GtkDialog* dialog)) + +// Dialogs +DECL(GtkWidget*, gtk_dialog_new, (void)) +DECL(GtkWidget*, gtk_dialog_add_button, (GtkDialog* dialog, const gchar* button_text, gint response_id )) +DECL(void, gtk_dialog_response, (GtkDialog* dialog, gint response_id )) +//DECL(GtkWidget*, gtk_dialog_new_with_buttons, (const gchar* title, GtkWindow* parent, GtkDialogFlags flags, const gchar* first_button_text, ...)) +//DECL(GtkWidget*, gtk_drop_down_new_from_strings, (const char* const* strings )) +DECL(GtkWidget*, gtk_combo_box_new, (void)); +DECL(GtkWidget*, gtk_combo_box_text_new, (void)) +DECL(void, gtk_combo_box_text_append, ( GtkComboBoxText* combo_box, const gchar* id, const gchar* text )) +DECL(GtkWidget*, gtk_dialog_get_content_area, (GtkDialog* dialog )) +DECL(gboolean, gtk_combo_box_set_active_id, ( GtkComboBox* combo_box, const gchar* active_id )) +DECL(const gchar*, gtk_combo_box_get_active_id, (GtkComboBox* combo_box)) + // GObject / GValue DECL(void, g_object_unref, (GObject* object)) +DECL(void, g_object_ref, (GObject* object)) DECL(void, g_object_set_property, (GObject* object, const gchar* property_name, const GValue* value)) DECL(GValue*, g_value_init, (GValue* value, GType g_type)) DECL(void, g_value_unset, (GValue* value)) DECL(void, g_value_set_int, (GValue* value, gint v_int)) +DECL(void, g_free, (gpointer mem)) +// Cursors +DECL(GdkCursor*, gdk_cursor_new_from_name, (GdkDisplay* display, const gchar* name )) +DECL(GdkCursor*, gdk_cursor_new, ( GdkCursorType cursor_type )) +DECL(void, gdk_window_set_cursor, (GdkWindow* window, GdkCursor* cursor )) // Menus @@ -338,6 +697,8 @@ DECL(GtkMenuItem *, gtk_menu_item_new, (void)); DECL(GtkMenuItem *, gtk_menu_item_new_with_label, (const gchar *label)); DECL(void, gtk_menu_shell_append, (GtkMenuShell* menu_shell, GtkWidget* child)) DECL(GtkWidget *, gtk_separator_menu_item_new, (void)) +DECL(void, gtk_menu_popup, (GtkMenu* menu, GtkWidget* parent_menu_shell, GtkWidget* parent_menu_item, + GtkMenuPositionFunc func, gpointer data, guint button, guint32 activate_time)) // Text Buffer / Widget DECL(GtkTextBuffer*, gtk_text_buffer_new, (GtkTextTagTable* table)) @@ -347,17 +708,42 @@ DECL(void, gtk_text_buffer_get_end_iter, (GtkTextBuffer* buffer, GtkTextIter* it DECL(GtkWidget*, gtk_text_view_new, (void)) DECL(GtkWidget*, gtk_text_view_new_with_buffer, ( GtkTextBuffer* buffer )) DECL(void, gtk_text_buffer_set_text, (GtkTextBuffer* buffer, const gchar* text, gint len )) +DECL(void, gtk_text_view_set_wrap_mode, (GtkTextView* text_view, GtkWrapMode wrap_mode )) // Titlebar DECL(GtkWidget*, gtk_header_bar_new, (void)) DECL(void, gtk_header_bar_set_custom_title, (GtkHeaderBar* bar, GtkWidget* title_widget)) -// Deprecated in Gtk3 +// Image +DECL(GtkWidget*, gtk_image_new_from_file, (const char* filename )) +DECL(GtkWidget*, gtk_image_new_from_pixbuf, (GdkPixbuf* pixbuf )) +DECL(void, gtk_image_set_from_pixbuf, ( GtkImage* image, GdkPixbuf* pixbuf )) +DECL(GdkPixbuf*, gdk_pixbuf_new_from_file, (const char* filename, GError** error)) +DECL(GdkPixbuf*, gdk_pixbuf_new_from_file_at_size, (const char* filename, int width, int height, GError** error)) +// Styles +DECL(GtkStyleContext*, gtk_widget_get_style_context, (GtkWidget* widget)) +DECL(char*, gtk_style_context_to_string, (GtkStyleContext* context, GtkStyleContextPrintFlags flags)) +DECL(GtkCssProvider*, gtk_css_provider_new, (void)) +DECL(gboolean, gtk_css_provider_load_from_data, (GtkCssProvider* css_provider, const gchar* data, gssize length, GError** error)) +DECL(void, gtk_style_context_add_provider, (GtkStyleContext* context, GtkStyleProvider* provider, guint priority)) +DECL(const GtkWidgetPath*, gtk_style_context_get_path, (GtkStyleContext* context)) +DECL(char*, gtk_widget_path_to_string, (const GtkWidgetPath* path)) + +// Deprecated in Gtk3 DECL(GtkStatusIcon*, gtk_status_icon_new, (void )) DECL(GtkStatusIcon*, gtk_status_icon_new_from_file, (const gchar* filename)) +DECL(void, gtk_widget_override_background_color, (GtkWidget* widget, GtkStateFlags state, const GdkRGBA* color)) +DECL(void, gtk_window_set_has_resize_grip, (GtkWindow* window, gboolean value )) #define g_signal_connect(instance, signal, c_handler, data) \ g_signal_connect_data(instance, signal, reinterpret_cast(c_handler), data, NULL, G_CONNECT_DEFAULT) +// WIN32 + +#ifdef _WIN32 +#include +DECL(HWND, gdk_win32_window_get_handle, (GdkWindow *window)); +#endif + #endif // GTK_IMPORTS_H diff --git a/gtkloader.cpp b/gtkloader.cpp index cfd62e2..21edad6 100644 --- a/gtkloader.cpp +++ b/gtkloader.cpp @@ -105,6 +105,8 @@ void GtkLoader::dlopen() "gtk-3-vs17", "glib-2.0-0", "gio-2.0-0", + "gdk-3-vs17", + "gdk_pixbuf-2.0-0", NULL }; int i; diff --git a/hide.png b/hide.png new file mode 100644 index 0000000000000000000000000000000000000000..e58aa473aab27d32b21845cfd757ea1f54a4d0e0 GIT binary patch literal 26647 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 + + + + + + + + + + + + \ No newline at end of file diff --git a/main.cpp b/main.cpp index 0a68b54..9e88434 100644 --- a/main.cpp +++ b/main.cpp @@ -14,7 +14,8 @@ static void activate (GtkApplication* app, gpointer user_data) GtkWidget *window; YellowNotes *notes = YELLOWNOTES(user_data); - GtkStatusIcon *tray = gtk_status_icon_new_from_file(notes->imageFile("yellownotes.svg").c_str()); + std::string img_file = notes->imageFile("yellownotes"); + GtkStatusIcon *tray = gtk_status_icon_new_from_file(img_file.c_str()); g_signal_connect(tray, "activate", on_tray_activate, notes); } @@ -22,6 +23,8 @@ int main(int argc, char **argv) { GtkLoader l; + srand(time(NULL)); // seed with current time + try { l.loadGtk(); } catch(std::string msg) { diff --git a/plus.png b/plus.png new file mode 100644 index 0000000000000000000000000000000000000000..7e0eb9aa9772ea07e540141fa52d655b00506f78 GIT binary patch literal 7459 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 literal 0 HcmV?d00001 diff --git a/plus.svg b/plus.svg new file mode 100644 index 0000000..2dfdc78 --- /dev/null +++ b/plus.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/tr.cpp b/tr.cpp new file mode 100644 index 0000000..e217f8b --- /dev/null +++ b/tr.cpp @@ -0,0 +1,94 @@ +#include "tr.h" +#include + +void tr::add(const char *sentence, ...) +{ + va_list args; + va_start(args, sentence); + + std::string sent(sentence); + + const char *tr = va_arg(args, char *); + while (tr != nullptr) { + std::string t(tr); + size_t pos = t.find(":"); + std::string lang = t.substr(0, pos); + std::string str = t.substr(pos + 1); + + std::unordered_map::iterator it; + it = _translations.find(lang); + if (it != _translations.end()) { + Translations_t *m = it->second; + std::pair p = { sent, str }; + m->insert(p); + } else { + Translations_t *m = new Translations_t(); + std::pair p = { sent, str }; + m->insert(p); + std::pair lp = { lang, m }; + _translations.insert(lp); + } + + tr = va_arg(args, char *); + } + + va_end(args); +} + +const char *tr::translate(const char *str) +{ + std::unordered_map::iterator it; + + it = _translations.find(_lang); + + if (it == _translations.end()) { + return str; + } else { + Translations_t *m = it->second; + Translations_t::iterator n_it; + std::string s(str); + n_it = m->find(s); + if (n_it == m->end()) { + return str; + } else { + return n_it->second.c_str(); + } + } +} + +void tr::setLang(const std::string &l) +{ + _lang = l; +} + +tr::tr() +{ + add("Quit", "nl:Beƫindigen", nullptr); + add("New Note", "nl:Nieuwe Notitie", nullptr); + add("Show Notes", "nl:Notities Presenteren", nullptr); + add("Hide Notes", "nl:Notities Verbergen", nullptr); + add("Reload Notes", "nl:Notities opnieuw laden", nullptr); + add("Setup", "nl:Instellingen", nullptr); + _lang = "en"; +} + +static tr *_t = nullptr; + +static void init() +{ + if (_t == nullptr) { + _t = new tr(); + } +} + +const char *_(const char *str) +{ + init(); + return _t->translate(str); +} + +void setLang(const std::string &lang) +{ + init(); + _t->setLang(lang); +} diff --git a/tr.h b/tr.h new file mode 100644 index 0000000..cf041ae --- /dev/null +++ b/tr.h @@ -0,0 +1,31 @@ +#ifndef TR_H +#define TR_H + +#include +#include + +typedef std::unordered_map Translations_t; + +class tr +{ +private: + std::unordered_map _translations; + std::string _lang; + +private: + void add(const char *sentence, ...); + +public: + const char *translate(const char *str); + +public: + void setLang(const std::string &l); + +public: + tr(); +}; + +const char *_(const char *str); +void setLang(const std::string &lang); + +#endif // TR_H diff --git a/yellownotes.cpp b/yellownotes.cpp index 57aeb22..e055c33 100644 --- a/yellownotes.cpp +++ b/yellownotes.cpp @@ -11,31 +11,74 @@ #include #endif +#ifdef _WIN32 +#include +#endif + #include +extern "C" { #include "gtk-imports.h" +} + +#include "tr.h" + +static void trim(std::string &s) { + size_t start = s.find_first_not_of(" \t\n\r"); + size_t end = s.find_last_not_of(" \t\n\r"); + + if (start == std::string::npos) + s.clear(); // String contains only whitespace + else + s = s.substr(start, end - start + 1); +} + class YellowNote { private: + YellowNotes *_notes; + GtkWindow *_note_widget; + + GtkWidget *_evt_box; GtkWidget *_note_box; - GtkTextBuffer *_buffer; - GtkWidget *_text_widget; - GtkWidget *_title_box; + GtkWidget *_frame; + + GtkWidget *_note_header; + GtkImage *_color_image; + GtkImage *_delete_image; + GtkImage *_plus_image; + GtkImage *_hide_image; GtkWidget *_title_label; - GtkHeaderBar *_note_header; - GtkWidget *_header_evt_box; + GtkWidget *_title_entry; + GtkWidget *_title_separator; + + GtkWidget *_scroll_widget; + GtkWidget *_text_widget; + GtkTextBuffer *_buffer; + std::string _filename; std::string _note; std::string _title; + bool _hidden; int _x; int _y; int _width; int _height; bool _in_transaction; + bool _editing_title; + + int _save_counter; + int _save_id; + + ColorType_t _color; + bool _color_changed; bool _moving; + bool _resize_right; + bool _resize_bottom; + bool _resize_edge; int _x_orig; int _y_orig; @@ -48,22 +91,49 @@ private: void updatePosition(); void updateHidden(); void updateSize(); + void updateColor(); + + void adjustTitle(bool mutate); + + void get_header_screen_coords(int &header_top, int &header_bottom); + void get_frame_screen_coords(int &frame_bottom, int &frame_right); + void get_screen_left_right(GtkWidget *widget, int &left, int &right); + + void nextColor(); + void deleteMe(); + void addNew(); + + void updateWidgetColors(GtkWidget *w); public: - void changed(); - void size_allocated(GtkAllocation *a); + void changed(GtkWidget *sender); + void size_allocated(GtkWidget *sender, GtkAllocation *a); public: - bool move_begin(GdkEventButton *evt); - bool move_end(GdkEventButton *evt); - bool moving(GdkEventMotion *evt); + void toFront(); + +public: + bool move_begin(GtkWidget *sender, GdkEventButton *evt); + bool move_end(GtkWidget *sender, GdkEventButton *evt); + bool moving(GtkWidget *sender, GdkEventMotion *evt); + bool titleEscape(GtkWidget *sender, GdkEventKey *key); + void titleEnter(GtkWidget *sender); + bool titleFocusOut(GtkWidget *sender, GdkEventFocus *evt); + void textChanged(void *sender); + bool textSaveTimeout(); + bool windowPresented(void *sender, GdkEventVisibility *evt); + void showNote(GtkWidget *sender); + +public: + std::string title(); + bool isHidden(); public: void load(); void save(); public: - YellowNote(const std::string &filename);; + YellowNote(YellowNotes *notes, const std::string &filename); ~YellowNote(); }; @@ -71,19 +141,49 @@ SIGNAL2(YellowNote, on_size_allocated, size_allocated, GtkAllocation) BSIGNAL2(YellowNote, on_button_press, move_begin, GdkEventButton); BSIGNAL2(YellowNote, on_button_release, move_end, GdkEventButton); BSIGNAL2(YellowNote, on_mouse_move, moving, GdkEventMotion); +SIGNAL(YellowNote, on_title_activate, titleEnter); +BSIGNAL2(YellowNote, on_title_escape, titleEscape, GdkEventKey); +BSIGNAL2(YellowNote, on_title_focus_out, titleFocusOut, GdkEventFocus); +BSIGNAL2(YellowNote, on_window_present, windowPresented, GdkEventVisibility); +SIGNAL(YellowNote, on_text_change, textChanged); +SIGNAL(YellowNote, on_show_note, showNote); + + +static gboolean on_text_save_timeout(gpointer data) +{ + YellowNote *n = reinterpret_cast(data); + return n->textSaveTimeout(); +} SIGNAL(YellowNotes, on_new_yellow, newNote) +SIGNAL(YellowNotes, on_show, showNotes); +SIGNAL(YellowNotes, on_reload, reloadNotes); +SIGNAL(YellowNotes, on_setup, setup); SIGNAL(YellowNotes, on_quit, quit) +SIGNAL(YellowNotes, on_hide_toplevel, topLevelHidden) +SIGNAL(YellowNotes, on_setup_ok, setupClose); +SIGNAL(YellowNotes, on_setup_close, setupCancel); +BSIGNAL2(YellowNotes, on_setup_del, setupDel, void); + std::string YellowNotes::imageFile(const char *name) { - - return appDir() + "/" + name; +#ifdef _WIN32 + std::string ext = ".png"; +#else + std::string ext = ".svg"; +#endif + return appDir() + "/" + name + ext; } std::string YellowNotes::appDir() { +#ifdef __linux std::string base = "/home/hans/src/yellownotes"; +#endif +#ifdef _WIN32 + std::string base = "c:/devel/yellownotes"; +#endif return base; } @@ -94,6 +194,11 @@ std::string YellowNotes::notesDir() const char *homedir = pw->pw_dir; #endif +#ifdef _WIN32 + char homedir[10240]; + snprintf(homedir, 10240, "%s%s", getenv("HOMEDRIVE"), getenv("HOMEPATH")); +#endif + std::string home_dir = homedir; std::string notes_dir = home_dir + "/yellownotes"; @@ -105,7 +210,77 @@ std::string YellowNotes::notesDir() return notes_dir; } -void YellowNotes::popupTrayMenu() +std::string YellowNotes::css(ColorType_t type) +{ + const char *bgs[] = { "#404040", // dark + "#faf32a", // yellow + "#fcbf56", // orange, + "#5df0f5", // blue + "#fc77f4", // Cyaan + "#74fc94", // greeen + "#f7bcbc", // red + "#cdcfd1" // grey + }; + + const char *fgs[] = { "white", + "black", + "black", + "black", + "black", + "black", + "black", + "black" + }; + + auto from_hex = [](std::string hex_num) { + return strtol(hex_num.c_str(), NULL, 16); + }; + + auto darker = [from_hex](std::string color) { + int red = from_hex(color.substr(1, 2)); + int green = from_hex(color.substr(3, 2)); + int blue = from_hex(color.substr(5, 2)); + float factor = 0.9; + red *= factor; + green *= factor; + blue *= factor; + char buf[20]; + sprintf(buf, "#%02x%02x%02x", red, green, blue); + std::string s = buf; + return s; + }; + + char font_size[20]; + sprintf(font_size, "%dpx", _font_size); + + std::string css = std::string() + + "label, box.horizontal, textview.view, textview.view text, frame, messagedialog.background {\n" + " background-color: " + bgs[type] + ";\n" + " color: " + fgs[type] + ";\n" + " font-family: sans;\n" + " font-size: " + font_size + ";\n" + "}\n" + "frame border {\n" + " border: none;\n" + " box-shadow: 5px 5px 5px " + darker(bgs[type]) + ";\n" + " margin: 5px;\n" + "}\n"; + + return css; +} + +int YellowNotes::fontSize() +{ + return _font_size; +} + +int YellowNotes::iconSize() +{ + return _font_size * 1.5; +} + + +void YellowNotes::popupTrayMenu(void *sender) { GtkMenu *tray_menu = reinterpret_cast(_tray_menu); @@ -114,22 +289,64 @@ void YellowNotes::popupTrayMenu() tray_menu = gtk_menu_new(); _tray_menu = reinterpret_cast(tray_menu); - GtkMenuItem *new_yellow = gtk_menu_item_new_with_label("New Note"); - GtkMenuItem *handle_notes = gtk_menu_item_new_with_label("Organize Notes"); + GtkMenuItem *new_yellow = gtk_menu_item_new_with_label(_("New Note")); + GtkMenuItem *show_notes = gtk_menu_item_new_with_label(_("Show Notes")); + GtkMenuItem *reload_notes = gtk_menu_item_new_with_label(_("Reload Notes")); GtkWidget *sep = gtk_separator_menu_item_new(); - GtkMenuItem *quit = gtk_menu_item_new_with_label("Quit"); + std::list hidden; + std::list h_notes; + std::list::iterator it = _notes.begin(); + while (it != _notes.end()) { + YellowNote *n = *it; + GtkWidget *m = gtk_menu_item_new_with_label(n->title().c_str()); + if (n->isHidden()) { + hidden.push_back(m); + h_notes.push_back(n); + } + it++; + } + + GtkWidget *sep1 = gtk_separator_menu_item_new(); + + GtkMenuItem *setup = gtk_menu_item_new_with_label(_("Setup")); + GtkMenuItem *quit = gtk_menu_item_new_with_label(_("Quit")); gtk_menu_shell_append(tray_menu, new_yellow); - gtk_menu_shell_append(tray_menu, handle_notes); + gtk_menu_shell_append(tray_menu, show_notes); + gtk_menu_shell_append(tray_menu, reload_notes); gtk_menu_shell_append(tray_menu, sep); + + std::list::iterator w_it = hidden.begin(); + while (w_it != hidden.end()) { + gtk_menu_shell_append(tray_menu, *w_it); + w_it++; + } + + gtk_menu_shell_append(tray_menu, sep1); + gtk_menu_shell_append(tray_menu, setup); gtk_menu_shell_append(tray_menu, quit); gtk_widget_show_all(tray_menu); g_signal_connect(new_yellow, "activate", on_new_yellow, this); + g_signal_connect(show_notes, "activate", on_show, this); + g_signal_connect(reload_notes, "activate", on_reload, this); + g_signal_connect(setup, "activate", on_setup, this); g_signal_connect(quit, "activate", on_quit, this); + w_it = hidden.begin(); + it = h_notes.begin(); + while(w_it != hidden.end()) { + g_signal_connect(*w_it, "activate", on_show_note, *it); + w_it++; + it++; + } +#ifdef __linux gtk_menu_popup_at_pointer(tray_menu, nullptr); +#endif +#ifdef _WIN32 + gtk_menu_popup(tray_menu, nullptr, nullptr, nullptr, nullptr, 0, 0); +#endif } void YellowNotes::clearNotes() @@ -141,8 +358,64 @@ void YellowNotes::clearNotes() } } +void YellowNotes::loadConfig() +{ + std::string notes_dir = notesDir(); + std::string cfg_file = notes_dir + "/yellownotes.cfg"; + std::filesystem::path p(cfg_file); + + auto add = [this](const char *k, const char *v) { + _cfg.insert(std::pair(std::string(k), std::string(v))); + }; + + _cfg.clear(); + add("lang", "en"); + + if (std::filesystem::is_regular_file(p)) { + FILE *f = fopen(cfg_file.c_str(), "rt"); + char buf[10240]; + char *b = fgets(buf, 10240, f); + while (b != nullptr) { + std::string e = std::string(b); + trim(e); + if (e != "") { + size_t pos = e.find("="); + std::string k = e.substr(0, pos); + std::string v = e.substr(pos + 1); + trim(k); + trim(v); + _cfg.erase(k); + _cfg.insert(std::pair(k, v)); + } + b = fgets(buf, 10240, f); + } + fclose (f); + } + + setLang(currentLang()); +} + +void YellowNotes::saveConfig() +{ + std::string notes_dir = notesDir(); + std::string cfg_file = notes_dir + "/yellownotes.cfg"; + + FILE *f = fopen(cfg_file.c_str(), "wt"); + if (f) { + std::unordered_map::iterator it; + it = _cfg.begin(); + while (it != _cfg.end()) { + fprintf(f, "%s=%s\n", it->first.c_str(), it->second.c_str()); + it++; + } + fclose(f); + } +} + void YellowNotes::loadNotes() { + gtk_widget_show_all(topLevel()); + clearNotes(); std::string notes_dir = notesDir(); @@ -159,110 +432,327 @@ void YellowNotes::loadNotes() { const auto full_name = entry.path().string(); - if (entry.is_regular_file()) + if (entry.is_regular_file() && full_name.rfind(".note") != std::string::npos) { const auto base_name = entry.path().filename().string(); if (base_name.rfind(".note") > 0) { - YellowNote *note = new YellowNote(full_name); + YellowNote *note = new YellowNote(this, full_name); _notes.push_back(note); } } } + + gtk_widget_hide(topLevel()); } -void YellowNotes::newNote() +void YellowNotes::showNotes(void *sender) { - std::string new_note_title = "New Note"; + std::list::const_iterator it = _notes.begin(); + while (it != _notes.end()) { + YellowNote *note = *it; + note->toFront(); + it++; + } + +} + +void YellowNotes::setupCancel(GtkWidget *sender) +{ + if (_dlg) { + gtk_widget_destroy(_dlg); + _dlg = nullptr; + _langs = nullptr; + } +} + +bool YellowNotes::setupDel(GtkWidget *sender, void *evt) +{ + setupCancel(sender); + return true; +} + +void YellowNotes::setupClose(GtkWidget *sender) +{ + if (_dlg != nullptr) { + std::cout << "hey" << std::endl; + gtk_dialog_response(_dlg, GTK_RESPONSE_OK); + std::string lang = std::string(gtk_combo_box_get_active_id(_langs)); + std::cout << "lang " << lang << std::endl; + setCurrentLang(lang); + gtk_widget_destroy(_dlg); + _dlg = nullptr; + _langs = nullptr; + saveConfig(); + } else { + std::cout << "close button" << std::endl; + } +} + +void YellowNotes::setup(void *sender) +{ + loadConfig(); + + GtkWidget *dlg = gtk_dialog_new(); + gtk_window_set_title(dlg, _("Yellownotes Setup")); + _dlg = dlg; + + GtkWidget *ok_btn = gtk_dialog_add_button(dlg, _("Ok"), GTK_RESPONSE_OK); + GtkWidget *content = gtk_dialog_get_content_area(dlg); + + GtkWidget *langs = gtk_combo_box_text_new(); + _langs = langs; + gtk_combo_box_text_append(langs, "en", "English"); + gtk_combo_box_text_append(langs, "nl", "Nederlands"); + + std::string current_lang = currentLang(); + gtk_combo_box_set_active_id(langs, current_lang.c_str()); + + GtkWidget *hbox = gtk_box_new(GtkOrientation::GTK_ORIENTATION_HORIZONTAL, 5); + + gtk_container_add(hbox, langs); + gtk_container_add(content, hbox); + + g_signal_connect(ok_btn, "clicked", on_setup_ok, this); + g_signal_connect(dlg, "close", on_setup_close, this); + g_signal_connect(dlg, "delete-event", on_setup_del, this); + + gtk_widget_show_all(dlg); +} + +void YellowNotes::reloadNotes(void *sender) +{ + std::list::const_iterator it = _notes.begin(); + while (it != _notes.end()) { + YellowNote *note = *it; + delete note; + it++; + } + _notes.clear(); + loadNotes(); + showNotes(sender); +} + + +void YellowNotes::newNote(void *sender) +{ + unsigned long long milliseconds_since_epoch = + std::chrono::system_clock::now().time_since_epoch() / + std::chrono::milliseconds(1); + + char buf[200]; + int r = rand() % 1000; + sprintf(buf, "%llu-%d", milliseconds_since_epoch, r); + + std::string new_note_file = buf; std::string notes_dir = notesDir(); - auto filename = [notes_dir](const std::string & title, int i) { + auto filename = [notes_dir](const std::string & fname, int i) { char s[20]; - sprintf(s, " %d", i); - std::string fn = notes_dir + "/" + title + s + ".note"; + sprintf(s, "%d", i); + std::string fn = notes_dir + "/" + fname + "-" + s + ".note"; return fn; }; - int i = 1; - std::filesystem::path p(filename(new_note_title, i)); + std::filesystem::path p(filename(new_note_file, i)); while(std::filesystem::is_regular_file(p)) { i += 1; - p = std::filesystem::path(filename(new_note_title, i)); + p = std::filesystem::path(filename(new_note_file, i)); } - YellowNote *note = new YellowNote(p); + YellowNote *note = new YellowNote(this, p.string()); _notes.push_back(note); note->show(); note->save(); } -void YellowNotes::quit() +void YellowNotes::quit(void *sender) { gtk_main_quit(); } +void YellowNotes::remove(YellowNote *n) +{ + _notes.remove(n); +} + +std::string YellowNotes::currentLang() +{ + std::string key("lang"); + return _cfg[key]; +} + +void YellowNotes::setCurrentLang(const std::string &l) +{ + std::string key("lang"); + _cfg.erase(key); + _cfg.insert(std::pair(key, l)); +} + +static int show_notes_timed(void *user_data) +{ + YellowNotes *notes = reinterpret_cast(user_data); + notes->showNotes(nullptr); + return false; +} + +void YellowNotes::topLevelHidden(GtkWidget *sender) +{ + g_timeout_add(500, show_notes_timed, this); +} + +GtkWindow *YellowNotes::topLevel() +{ + if (_toplevel == nullptr) { + _toplevel = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_show_all(_toplevel); + g_signal_connect(_toplevel, "hide", on_hide_toplevel, this); + } + return _toplevel; +} + YellowNotes::YellowNotes(void *app) { _app = app; _tray_menu = nullptr; + _font_size = 15; + _toplevel = nullptr; + loadConfig(); } YellowNotes::~YellowNotes() { if (_tray_menu) { gtk_widget_destroy(reinterpret_cast(_tray_menu)); } clearNotes(); + gtk_widget_destroy(_toplevel); } //////////////////////////////////////////////////////////////////////////////////////////////////// /// YellowNote implementation //////////////////////////////////////////////////////////////////////////////////////////////////// -YellowNote::YellowNote(const std::string &filename) { +YellowNote::YellowNote(YellowNotes *notes, const std::string &filename) +{ + _notes = notes; _filename = filename; - _title = ""; - _x = -1; - _y = -1; - _width = -1; - _height = -1; + _title = _("New Note"); + _x = 200; + _y = 300; + _width = 300; + _height = 200; _hidden = false; + _editing_title = false; + _save_counter = 0; + _save_id = -1; _moving = false; + _resize_bottom = false; + _resize_edge = false; + _resize_right = false; + + _color = ColorType_t::YELLOW; + _color_changed = false; + + _note_widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_set_can_focus(_note_widget, true); + gtk_window_set_decorated(_note_widget, false); + gtk_window_set_type_hint(_note_widget, GDK_WINDOW_TYPE_HINT_POPUP_MENU); + gtk_window_set_transient_for(_note_widget, _notes->topLevel()); + + _scroll_widget = gtk_scrolled_window_new(nullptr, nullptr); + gtk_widget_set_vexpand(_scroll_widget, true); - _note_widget = gtk_window_new(GtkWindowType::GTK_WINDOW_TOPLEVEL); _buffer = gtk_text_buffer_new(nullptr); _text_widget = gtk_text_view_new_with_buffer(_buffer); + gtk_text_view_set_wrap_mode(_text_widget, GTK_WRAP_WORD); - _header_evt_box = gtk_event_box_new(); - _note_header = gtk_header_bar_new(); + _evt_box = gtk_event_box_new(); + + _note_header = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); - gtk_window_set_decorated(_note_widget, false); _note_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); - //_title_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); _title_label = gtk_label_new(_title.c_str()); gtk_label_set_ellipsize(_title_label, PANGO_ELLIPSIZE_END); - gtk_header_bar_set_custom_title(_note_header, _title_label); + gtk_widget_set_hexpand(_title_label, true); - //gtk_container_add(_title_box, _title_label); - gtk_container_add(_note_box, _header_evt_box); - gtk_container_add(_header_evt_box, _note_header); - gtk_container_add(_note_box, _text_widget); - gtk_container_add(_note_widget, _note_box); + _title_entry = gtk_entry_new(); + gtk_widget_set_hexpand(_title_entry, true); + + _title_separator = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); + + _frame = gtk_frame_new(nullptr); + gtk_frame_set_shadow_type(_frame, GtkShadowType::GTK_SHADOW_OUT); + + int height = _notes->iconSize(); + int width = height; + + GdkPixbuf *color_pixbuf = gdk_pixbuf_new_from_file_at_size(notes->imageFile("color").c_str(), + width, height, nullptr + ); + _color_image = gtk_image_new_from_pixbuf(color_pixbuf); + g_object_unref(color_pixbuf); + + GdkPixbuf *delete_pixbuf = gdk_pixbuf_new_from_file_at_size(notes->imageFile("delete").c_str(), + width, height, nullptr + ); + _delete_image = gtk_image_new_from_pixbuf(delete_pixbuf); + gtk_widget_set_halign(_delete_image, GtkAlign::GTK_ALIGN_END); + g_object_unref(delete_pixbuf); + + GdkPixbuf *plus_pixbuf = gdk_pixbuf_new_from_file_at_size(notes->imageFile("plus").c_str(), + width, height, nullptr + ); + _plus_image = gtk_image_new_from_pixbuf(plus_pixbuf); + gtk_widget_set_halign(_plus_image, GtkAlign::GTK_ALIGN_END); + g_object_unref(plus_pixbuf); + + GdkPixbuf *hide_pixbuf = gdk_pixbuf_new_from_file_at_size(notes->imageFile("hide").c_str(), + width, height, nullptr + ); + _hide_image = gtk_image_new_from_pixbuf(hide_pixbuf); + gtk_widget_set_halign(_plus_image, GtkAlign::GTK_ALIGN_END); + g_object_unref(hide_pixbuf); + + gtk_container_add(_note_header, _color_image); + gtk_container_add(_note_header, _title_label); + gtk_container_add(_note_header, _plus_image); + gtk_container_add(_note_header, _delete_image); + gtk_container_add(_note_header, _hide_image); + + gtk_container_add(_scroll_widget, _text_widget); + + gtk_container_add(_note_box, _note_header); + gtk_container_add(_note_box, _title_separator); + gtk_container_add(_note_box, _scroll_widget); + + gtk_container_add(_frame, _note_box); + gtk_container_add(_evt_box, _frame); + gtk_container_add(_note_widget, _evt_box); gtk_widget_show_all(_note_widget); - { - GdkWindow *w = gtk_widget_get_window(_title_label); - int mask = GDK_BUTTON1_MOTION_MASK + GDK_BUTTON_PRESS_MASK + GDK_BUTTON_RELEASE_MASK; - gdk_window_set_events(w, static_cast(mask)); - } - + //GdkWindow *window = gdk_window_get_effective_toplevel(gtk_widget_get_window(_note_widget)); + //gdk_window_set_events(window, static_cast(gdk_window_get_events(window) | GDK_VISIBILITY_NOTIFY_MASK)); + //gdk_window_set_override_redirect(window, true); g_signal_connect(_note_widget, "size_allocate", on_size_allocated, this); - g_signal_connect(_header_evt_box, "button_press_event", on_button_press, this); - g_signal_connect(_header_evt_box, "button_release_event", on_button_release, this); - g_signal_connect(_header_evt_box, "motion_notify_event", on_mouse_move, this); + g_signal_connect(_evt_box, "button_press_event", on_button_press, this); + g_signal_connect(_evt_box, "button_release_event", on_button_release, this); + g_signal_connect(_evt_box, "motion_notify_event", on_mouse_move, this); + g_signal_connect(_title_entry, "activate", on_title_activate, this); + g_signal_connect(_title_entry, "key_press_event", on_title_escape, this); + g_signal_connect(_title_entry, "focus_out_event", on_title_focus_out, this); + g_signal_connect(_buffer, "changed", on_text_change, this); + g_signal_connect(_note_widget, "visibility_notify_event", on_window_present, this); + + // Keep label and entry of title alive + g_object_ref(_title_label); + g_object_ref(_title_entry); + g_object_ref(_delete_image); + g_object_ref(_plus_image); + g_object_ref(_hide_image); load(); @@ -271,10 +761,81 @@ YellowNote::YellowNote(const std::string &filename) { YellowNote::~YellowNote() { + g_object_unref(_title_label); + g_object_unref(_title_entry); + g_object_unref(_delete_image); + g_object_unref(_plus_image); + g_object_unref(_hide_image); gtk_widget_destroy(_note_widget); _note_widget = nullptr; } +void YellowNote::updateWidgetColors(GtkWidget *w) +{ + auto set_style = [this](GtkWidget *widget) { + GtkStyleContext *c = gtk_widget_get_style_context(widget); + const char *style = gtk_style_context_to_string(c, GTK_STYLE_CONTEXT_PRINT_RECURSE); + GtkCssProvider *css = gtk_css_provider_new(); + gtk_style_context_add_provider(c, css, GTK_STYLE_PROVIDER_PRIORITY_USER); + std::string widget_css = _notes->css(_color); + gtk_css_provider_load_from_data(css, widget_css.c_str(), widget_css.size(), nullptr); + }; + + set_style(w); +} + +void YellowNote::updateColor() +{ + + auto set_style = [this](GtkWidget *w) { + this->updateWidgetColors(w); + }; + + set_style(_title_label); + set_style(_note_header); + set_style(_text_widget); + set_style(_note_widget); + set_style(_frame); +} + +void YellowNote::nextColor() +{ + int c = _color; + c += 1; + _color = static_cast(c); + if (_color > ColorType_t::LAST) { + _color = ColorType_t::FIRST; + } + save(); + updateColor(); +} + +void YellowNote::addNew() +{ + _notes->newNote(this); +} + +void YellowNote::deleteMe() +{ + GtkWidget *msg = gtk_message_dialog_new(_note_widget, + GtkDialogFlags::GTK_DIALOG_MODAL, + GtkMessageType::GTK_MESSAGE_QUESTION, + GtkButtonsType::GTK_BUTTONS_YES_NO, + "%s", "Are you sure you want to delete this note?" + ); + updateWidgetColors(msg); + + int response = gtk_dialog_run(msg); + gtk_widget_destroy (msg); + + if (response == GTK_RESPONSE_YES) { + _notes->remove(this); + std::filesystem::path p(_filename); + std::filesystem::remove(p); + delete this; + } +} + void YellowNote::updateTitle() { gtk_label_set_label(_title_label, _title.c_str()); @@ -296,21 +857,34 @@ void YellowNote::updateSize() gtk_window_resize(_note_widget, _width, _height); } +void YellowNote::showNote(GtkWidget *sender) +{ + show(); +} + void YellowNote::show() { gtk_widget_show_all(_note_widget); + _hidden = false; + save(); } void YellowNote::hide() { gtk_widget_hide(_note_widget); + _hidden = true; + save(); } - -void YellowNote::changed() +void YellowNote::changed(GtkWidget *sender) { bool sv = false; + if (_color_changed) { + _color_changed = true; + sv = true; + } + bool hidden = !gtk_widget_is_visible(_note_widget); if (hidden != _hidden) { _hidden = hidden; @@ -344,7 +918,6 @@ void YellowNote::changed() sv = true; } - const char *c_t = gtk_label_get_text (_title_label); if (c_t != nullptr) { std::string t(c_t); @@ -357,42 +930,317 @@ void YellowNote::changed() if (sv) { save(); } } -void YellowNote::size_allocated(GtkAllocation *a) +void YellowNote::size_allocated(GtkWidget *sender, GtkAllocation *a) { - changed(); + changed(sender); } -bool YellowNote::move_begin(GdkEventButton *evt) +void YellowNote::toFront() { - std::cout << "move_begin" << std::endl; - _moving = true; - _x_orig = evt->x_root; - _y_orig = evt->y_root; - return true; + if (_hidden) { + gtk_window_move(_note_widget, _x, _y); + gtk_widget_hide(_note_widget); + } else { + gtk_window_present(_note_widget); + gtk_window_move(_note_widget, _x, _y); + } } -bool YellowNote::move_end(GdkEventButton *evt) +void YellowNote::get_header_screen_coords(int &header_top, int &header_bottom) { - std::cout << "move_end" << std::endl; - _moving = false; - return true; + int left, top; + gtk_window_get_position(_note_widget, &left, &top); + header_top = top; + + GtkAllocation alloc; + gtk_widget_get_allocation(_note_header, &alloc); + header_bottom = alloc.y + alloc.height + top; } -bool YellowNote::moving(GdkEventMotion *evt) +void YellowNote::get_frame_screen_coords(int &frame_bottom, int &frame_right) +{ + int left, top; + gtk_window_get_position(_note_widget, &left, &top); + GtkAllocation alloc; + + gtk_widget_get_allocation(_scroll_widget, &alloc); + frame_bottom = alloc.y + alloc.height + top; + frame_right = alloc.x + alloc.width + left; +} + +void YellowNote::get_screen_left_right(GtkWidget *widget, int &left, int &right) +{ + int wleft, wtop; + gtk_window_get_position(_note_widget, &wleft, &wtop); + GtkAllocation alloc; + + gtk_widget_get_allocation(widget, &alloc); + left = wleft + alloc.x; + right = left + alloc.width; +} + +void YellowNote::adjustTitle(bool mutate) +{ + if (!_editing_title) { return; } + _editing_title = false; + + if (mutate) { + std::string _old_title = _title; + _title = gtk_entry_get_text(_title_entry); + trim(_title); + gtk_label_set_label(_title_label, _title.c_str()); + save(); + } + + gtk_container_remove(_note_header, _title_entry); + gtk_container_add(_note_header, _title_label); + gtk_container_remove(_note_header, _plus_image); + gtk_container_add(_note_header, _plus_image); + gtk_container_remove(_note_header, _delete_image); + gtk_container_add(_note_header, _delete_image); + gtk_container_remove(_note_header, _hide_image); + gtk_container_add(_note_header, _hide_image); +} + +bool YellowNote::windowPresented(void *sender, GdkEventVisibility *evt) // TODO according to docs this must not be a pointer +{ + return false; +} + +std::string YellowNote::title() +{ + return _title; +} + +bool YellowNote::isHidden() +{ + return _hidden; +} + +void YellowNote::textChanged(void *sender) +{ + if (_in_transaction) return; + + std::cout << "Changed " << _save_id << std::endl; + _save_counter++; + if (_save_id == -1) { + std::cout << "Starting save timer" << std::endl; + _save_id = _save_counter; + g_timeout_add(1000, on_text_save_timeout, this); + } +} + +bool YellowNote::textSaveTimeout() +{ + if (_save_counter != _save_id) { + std::cout << "Something changed" << std::endl; + _save_id = _save_counter; + g_timeout_add(1000, on_text_save_timeout, this); + return false; + } else { + _save_id = -1; + std::cout << "Saving" << std::endl; + save(); + return false; + } +} + +void YellowNote::titleEnter(GtkWidget *sender) +{ + adjustTitle(true); +} + +bool YellowNote::titleEscape(GtkWidget *sender, GdkEventKey *key) +{ + if (key->keyval == GDK_KEY_Escape && _editing_title) { + adjustTitle(false); + return true; + } + return false; +} + +bool YellowNote::titleFocusOut(GtkWidget *sender, GdkEventFocus *evt) +{ + if (_editing_title) { + adjustTitle(false); + return true; + } + return false; +} + +#define AROUND(c, n) ((c >= (n - threshold)) && (c <= (n + threshold))) + +bool YellowNote::move_begin(GtkWidget *sender, GdkEventButton *evt) { int x = evt->x_root; int y = evt->y_root; - int dx = x - _x_orig; - int dy = y - _y_orig; + int header_top, header_bottom; + get_header_screen_coords(header_top, header_bottom); - std::cout << "moving " << x << ", " << y << ", dx = " << dx << ", dy = " << dy << ", _x = " << _x << ", _y = " << y << std::endl; + int frame_bottom, frame_right; + get_frame_screen_coords(frame_bottom, frame_right); - //gtk_window_move(_note_widget, _x + dx, _y + dy); + int color_left, color_right; + get_screen_left_right(_color_image, color_left, color_right); + + int delete_left, delete_right; + get_screen_left_right(_delete_image, delete_left, delete_right); + + int plus_left, plus_right; + get_screen_left_right(_plus_image, plus_left, plus_right); + + int hide_left, hide_right; + get_screen_left_right(_hide_image, hide_left, hide_right); + + if (y >= header_top && y <= header_bottom) { + if (x >= color_left && x <= color_right) { + nextColor(); + return true; + } + if (x >= plus_left && x <= plus_right) { + addNew(); + return true; + } + if (x >= hide_left && x <= hide_right) { + hide(); + return true; + } + if (x >= delete_left && x <= delete_right) { + deleteMe(); + return true; + } + } + + if (evt->type == GDK_2BUTTON_PRESS) { + gtk_container_remove(_note_header, _title_label); + gtk_container_add(_note_header, _title_entry); + gtk_container_remove(_note_header, _plus_image); + gtk_container_add(_note_header, _plus_image); + gtk_container_remove(_note_header, _delete_image); + gtk_container_add(_note_header, _delete_image); + gtk_container_remove(_note_header, _hide_image); + gtk_container_add(_note_header, _hide_image); + gtk_widget_show(_title_entry); + gtk_entry_set_text(_title_entry, _title.c_str()); + gtk_widget_grab_focus(_title_entry); + _editing_title = true; + return true; + } + + if (y >= header_top && y <= header_bottom) { + _moving = true; + _x_orig = evt->x; + _y_orig = evt->y; + return true; + } + + int threshold = 8; + + if (AROUND(y, frame_bottom) && AROUND(x, frame_right)) { + _resize_edge = true; + } else if (AROUND(y, frame_bottom)) { + _resize_bottom = true; + } else if (AROUND(x, frame_right)) { + _resize_right = true; + } return false; } +bool YellowNote::move_end(GtkWidget *sender, GdkEventButton *evt) +{ + if (_moving) { + _moving = false; + return true; + } + + if (_resize_edge || _resize_bottom || _resize_right) { + _resize_edge = false; + _resize_bottom = false; + _resize_right = false; + return true; + } + return false; +} + +bool YellowNote::moving(GtkWidget *sender, GdkEventMotion *evt) +{ + int x = evt->x_root; + int y = evt->y_root; + + if (_moving) { + int the_x = x - _x_orig; + int the_y = y - _y_orig; + gtk_window_move(_note_widget, the_x, the_y); + return true; + } + + if (_resize_bottom || _resize_right || _resize_edge) { + if (_resize_edge) { + int left, top; + gtk_window_get_position(_note_widget, &left, &top); + int width = x - left; + int height = y - top; + if (width < 100) { width = 100; } + if (height < 60) { height = 60; } + gtk_window_resize(_note_widget, width, height); + return true; + } + + if (_resize_right) { + int left, top; + gtk_window_get_position(_note_widget, &left, &top); + int w, h; + gtk_window_get_size(_note_widget, &w, &h); + int width = x - left; + if (width < 100) { width = 100; } + gtk_window_resize(_note_widget, width, h); + return true; + } + + if (_resize_bottom) { + int left, top; + gtk_window_get_position(_note_widget, &left, &top); + int w, h; + gtk_window_get_size(_note_widget, &w, &h); + int height = y - top; + if (height < 60) { height = 60; } + gtk_window_resize(_note_widget, w, height); + return true; + } + } + + int frame_bottom, frame_right; + get_frame_screen_coords(frame_bottom, frame_right); + + int header_top, header_bottom; + get_header_screen_coords(header_top, header_bottom); + + GdkWindow *window = gtk_widget_get_window(_frame); + GdkCursor *c; + + int threshold = 8; + + if (y >= header_top && y <= header_bottom) { + c = gdk_cursor_new(GDK_LEFT_PTR); + } else if (AROUND(x, frame_right) && AROUND(y, frame_bottom)) { + c = gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER); + } else if (AROUND(x, frame_right)) { + c = gdk_cursor_new(GDK_RIGHT_SIDE); + } else if (AROUND(y, frame_bottom)) { + c = gdk_cursor_new(GDK_BOTTOM_SIDE); + } else { + c = nullptr; + } + + gdk_window_set_cursor(window, c); + if (c) g_object_unref(c); + + return false; +} + +#define YELLOWNOTE_VERSION 1 void YellowNote::load() { @@ -409,8 +1257,6 @@ void YellowNote::load() _in_transaction = true; std::filesystem::path p(_filename); - const auto base_name = p.filename().string(); - _title = base_name.substr(0, base_name.rfind(".note")); size_t s = 0; if (std::filesystem::is_regular_file(p)) { @@ -419,15 +1265,27 @@ void YellowNote::load() FILE *f = fopen(_filename.c_str(), "rt"); if (f) { + int version = readInt(f, -1); + _hidden = readInt(f, -1); _x = readInt(f, 200); _y = readInt(f, 200); _width = readInt(f, 300); _height = readInt(f, 200); - int pos = ftell(f); + int color; + color = readInt(f, ColorType_t::YELLOW); + _color = static_cast(color); + char *buf = static_cast(malloc(s)); memset(buf, 0, s); + + fgets(buf, s, f); + _title = buf; + trim(_title); + + memset(buf, 0, s); + int pos = ftell(f); int bytes = s - pos; fread(buf, bytes, 1, f); @@ -437,9 +1295,10 @@ void YellowNote::load() } updateTitle(); - updateHidden(); + updateColor(); updatePosition(); updateSize(); + updateHidden(); _in_transaction = false; } @@ -453,11 +1312,14 @@ void YellowNote::save() std::filesystem::path p(_filename); FILE *f = fopen(_filename.c_str(), "wt"); if (f) { + fprintf(f, "%d\n", YELLOWNOTE_VERSION); fprintf(f, "%d\n", _hidden); fprintf(f, "%d\n", _x); fprintf(f, "%d\n", _y); fprintf(f, "%d\n", _width); fprintf(f, "%d\n", _height); + fprintf(f, "%d\n", _color); + fprintf(f, "%s\n", _title.c_str()); GtkTextIter start, end; gtk_text_buffer_get_start_iter(_buffer, &start); @@ -465,7 +1327,7 @@ void YellowNote::save() gchar *text = gtk_text_buffer_get_text(_buffer, &start, &end, false); fprintf(f, "%s", text); fclose(f); - free(text); + g_free(text); } } diff --git a/yellownotes.h b/yellownotes.h index 91ee34f..11d02d5 100644 --- a/yellownotes.h +++ b/yellownotes.h @@ -3,15 +3,43 @@ #include #include +#include + +extern "C" { +#include "gtk-imports.h" +} class YellowNote; +typedef enum { + DARK = 0, + FIRST= DARK, + YELLOW, + ORANGE, + BLUE, + CYAAN, + GREEN, + RED, + GREY, + LAST = GREY +} ColorType_t; + class YellowNotes { private: void *_tray_menu; void *_app; + void *_dlg; + void *_langs; + std::list _notes; + int _font_size; + GtkWindow *_toplevel; + std::unordered_map _cfg; + +private: + void loadConfig(); + void saveConfig(); public: void loadNotes(); @@ -21,11 +49,27 @@ public: std::string imageFile(const char *name); std::string appDir(); std::string notesDir(); + std::string css(ColorType_t type); + int fontSize(); + int iconSize(); + GtkWindow *topLevel(); public: - void popupTrayMenu(); - void newNote(); - void quit(); + void popupTrayMenu(void *sender); + void newNote(void *sender); + void showNotes(void *sender); + void reloadNotes(void *sender); + void quit(void *sender); + void topLevelHidden(GtkWidget *sender); + void setup(void *sender); + void setupClose(GtkWidget *sender); + void setupCancel(GtkWidget *sender); + bool setupDel(GtkWidget *sender, void *evt); + void remove(YellowNote *n); + +public: + std::string currentLang(); + void setCurrentLang(const std::string &l); public: YellowNotes(void *app); @@ -34,12 +78,15 @@ public: #define YELLOWNOTES(obj) reinterpret_cast(obj) #define SIGNAL(type, func, member) \ - static void func(GObject *obj, gpointer user_data) { type *o = reinterpret_cast(user_data); o->member(); } + static void func(GObject *obj, gpointer user_data) { type *o = reinterpret_cast(user_data); o->member(obj); } + +#define BSIGNAL(type, func, member) \ + static gboolean func(GObject *obj, gpointer user_data) { std::cout << user_data << std::endl; type *o = reinterpret_cast(user_data); return o->member(obj); } #define SIGNAL2(type, func, member, argtype) \ - static void func(GObject *obj, void *arg, gpointer user_data) { type *o = reinterpret_cast(user_data); o->member(reinterpret_cast(arg)); } + static void func(GObject *obj, void *arg, gpointer user_data) { type *o = reinterpret_cast(user_data); o->member(obj, reinterpret_cast(arg)); } #define BSIGNAL2(type, func, member, argtype) \ - static gboolean func(GObject *obj, void *arg, gpointer user_data) { type *o = reinterpret_cast(user_data); return o->member(reinterpret_cast(arg)); } + static gboolean func(GObject *obj, void *arg, gpointer user_data) { type *o = reinterpret_cast(user_data); return o->member(obj, reinterpret_cast(arg)); } #endif // YELLOWNOTES_H