ScheduleGadget

Share your advanced PureBasic knowledge/code with the community.
jesperbrannmark
Enthusiast
Enthusiast
Posts: 536
Joined: Mon Feb 16, 2009 10:42 am
Location: sweden
Contact:

ScheduleGadget

Post by jesperbrannmark »

Since everyone is releasing new gadgets under Canvasgadget I couldn't resist it.
Its not really finished, but its a good start.
Calendargadget is already taken as a name, dategadget is also taken.. Calendar Canvas Gadget is also taken http://www.purebasic.fr/english/viewtopic.php?t=46349 and so is datepicker http://www.purebasic.fr/english/viewtopic.php?t=46300
I did a full week calendar before, but working with canvasgadget is so much nicer than sprites http://www.purebasic.fr/english/viewtopic.php?t=46369

So here it is - ScheduleGadget. A very early attempt on competing with Apple and their iCal :wink:

Code: Select all

; ScheduleGadget.pb by Jesper B.
; Creates a dayview calendar.
;
; Usage:
; *Doubleclick To add a meeting at current hour from computer time.
; *Leftclick to select a meeting -> drag/drop and write to change meeting name (+esc, enter, backspace can be used).
; *Rightclick to remove a meeting.
; Unitsperhour (2 = one tick every 30 minutes, 4 = one tick every 15 minutes, 6=one tick every 10 minutes etc)
; 
;
; Still to do: 
; *Most functions only work with full hours, not minutes at the moment.
; *End time is not taken in count yet.
; *Expand the ScheduleGadget_Add() to handle text, time etc.
; *Expand the ScheduleGadget_Remove() to be able to specify what event to remove.
; *Several day (3 day, weekview, monthview etc) and several calendars (multiple staff ie) view.
; *Collision check (right now two meetings will just show up on top of each other).
; *Zoom function
;
; Version: 0.1
; 
; License: May not be ported to other languages, any contributions/changes/alterations 
; to code would probably be appreciated in the Purebasic community. Use as you like with that in mind.
;
Enumeration
  #Schedule_NewEvent
  #Schedule_LeftClick
  #Schedule_LeftDoubleClick
  #Schedule_RightClick
EndEnumeration
Enumeration
  #calendar_normaltext
  #calendar_smalltext
EndEnumeration
LoadFont(#calendar_normaltext,"Arial",12)
LoadFont(#calendar_smalltext,"Arial",10)

Structure SCHEDULE_ITEM_INFO
  text.s
  time_start.i
  time_end.i
  colour.l
  x.i
  y.i
  w.i
  h.i
EndStructure

Structure SCHEDULE_INFO
  *topgadget
  *scrollareagadget
  *canvasgadget
  flags.l
  UnitsPerHour.b
  DateShown.i
  SelectedItem.i
  List item.SCHEDULE_ITEM_INFO()
EndStructure
Global NewList SGs.SCHEDULE_INFO()
Procedure ScheduleGadget_Repaint(*sg) 
  PushListPosition(SGs())
  ChangeCurrentElement(SGs(),*sg)
  If StartDrawing(CanvasOutput(SGs()\topgadget))
    ;//PAINT TOP
    Box(0,0,GadgetWidth(SGs()\topgadget),50,RGB(255,255,255))
    Box(0,0,GadgetWidth(SGs()\topgadget),80,RGB($BB,$CC,$FF))     
    Box(50,5,GadgetWidth(SGs()\topgadget)-80,25,RGB($FA,$D1,$63)) 
    DrawingMode(#PB_2DDrawing_Transparent)
    t.s=FormatDate("%yyyy-%mm-%dd",SGs()\DateShown)
    DrawText((GadgetWidth(SGs()\topgadget)/2)-(TextWidth(t.s)/2),5,t.s,RGB($66,$66,$66))
    DrawingMode(#PB_2DDrawing_Default)
    StopDrawing()
    ;//PAINT BACKGROUND
    StartDrawing(CanvasOutput(SGs()\canvasgadget))
    Box(5,0,45,GadgetHeight(SGs()\canvasgadget)-65,RGB($F6,$F9,$FC))
    Box(50,0,(GadgetWidth(SGs()\canvasgadget)-60),GadgetHeight(SGs()\canvasgadget)-100,RGB(210,210,215))
    DrawingMode(#PB_2DDrawing_Transparent)
    For a=1 To 24
      Line(50,0+(GadgetHeight(SGs()\canvasgadget)-95)/(24*a),GadgetWidth(SGs()\canvasgadget),1,RGB(244, 244, 244))
      Line(5,0+(GadgetHeight(SGs()\canvasgadget)-95)/(24*a),40,1,RGB($BB,$CC,$FF)) 
      DrawingFont(FontID(#calendar_normaltext))
      DrawText(31,10+(GadgetHeight(SGs()\canvasgadget)-95)/(24)*a,RSet(Str(a),2,"0"),RGB($66,$66,$66))    
      DrawingFont(FontID(#calendar_smalltext))
      For j=0 To SGs()\UnitsPerHour-1
        DrawingMode(#PB_2DDrawing_Default)
        y.f=(GadgetHeight(SGs()\canvasgadget)-95)/(24)*(a+(j/SGs()\UnitsPerHour))
        Line(50,y.f,GadgetWidth(SGs()\canvasgadget),1,RGB(244, 244, 244))
        DrawingMode(#PB_2DDrawing_Transparent)
        If j
          DrawText(41-TextWidth(RSet(Str(((60/SGs()\UnitsPerHour)*j)),2,"0")),-5+y.f,RSet(Str(((60/SGs()\UnitsPerHour)*j)),2,"0"),RGB($aa,$aa,$aa))    
        EndIf
      Next
    Next
    DrawingMode(#PB_2DDrawing_Default)
    ;//PAINT MEETINGS
    ForEach SGs()\item()
      start.s=FormatDate("%yyyy-%mm-%dd %hh:%ii:%ss",SGs()\item()\time_start)
      stop.s=FormatDate("%yyyy-%mm-%dd %hh:%ii:%ss",SGs()\item()\time_end)
      SGs()\item()\x=60
      SGs()\item()\y=((GadgetHeight(SGs()\canvasgadget)-95)/24)*(Val(Mid(start,12,2))+(Val(Mid(start,15,2))/60))
      SGs()\item()\w=GadgetWidth(SGs()\CanvasGadget)-80
      SGs()\item()\h=100
      DrawingMode(#PB_2DDrawing_AlphaBlend)
      If SGs()\SelectedItem=ListIndex(SGs()\item())
        If GetGadgetAttribute(SGs()\canvasgadget,#PB_Canvas_Buttons) & #PB_Canvas_LeftButton
          y2=(GetGadgetAttribute(SGs()\canvasgadget,#PB_Canvas_MouseY))
          For a=1 To 24
            For j=1 To SGs()\UnitsPerHour-1
              y.f=(GadgetHeight(SGs()\canvasgadget)-95)/(24)*(a+(j/SGs()\UnitsPerHour))
              If y.f>y2
                start.s=FormatDate("%yyyy-%mm-%dd",SGs()\item()\time_start)+" "+RSet(Str(a),2,"0")+":00:00"
                Break 2
              EndIf
            Next
          Next
          SGs()\item()\time_start=ParseDate("%yyyy-%mm-%dd %hh:%ii:%ss",start)
          SGs()\item()\y=((GadgetHeight(SGs()\canvasgadget)-95)/24)*(Val(Mid(start,12,2))+(Val(Mid(start,15,2))/60))
        EndIf
        Box(SGs()\item()\x,SGs()\item()\y,SGs()\item()\w,SGs()\item()\h,RGBA($144,$144,$44,240))
      EndIf
      RoundBox(SGs()\item()\x,SGs()\item()\y,SGs()\item()\w,SGs()\item()\h,5,5,RGBA($44,$44,$44,120))
      RoundBox(SGs()\item()\x+1,SGs()\item()\y+1,SGs()\item()\w-2,SGs()\item()\h-2,5,5,SGs()\item()\colour)
      DrawingMode(#PB_2DDrawing_Transparent)
      DrawingFont(FontID(#calendar_normaltext))      
      DrawingMode(#PB_2DDrawing_Transparent)
      DrawText(5+SGs()\item()\x,5+SGs()\item()\y,start,RGBA(0,0,0,12))
      DrawingFont(FontID(#calendar_smalltext))      
      DrawText(5+SGs()\item()\x,15+SGs()\item()\y,SGs()\item()\text,RGBA(0,0,0,12))
      DrawingMode(#PB_2DDrawing_Default)
    Next    
    StopDrawing()
  EndIf  
  PopListPosition(SGs())
EndProcedure
Procedure ScheduleGadget_HandleEvent(*sg) 
  PushListPosition(SGs())
  ChangeCurrentElement(SGs(),*sg)
  mx = GetGadgetAttribute(SGs()\canvasgadget, #PB_Canvas_MouseX)
  my = GetGadgetAttribute(SGs()\canvasgadget, #PB_Canvas_MouseY)
  Select EventType()
    Case #PB_EventType_MouseEnter      ; The mouse cursor entered the gadget
      If SGs()\SelectedItem<>-1
        repaint=#True
      EndIf
      SGs()\SelectedItem=-1
    Case  #PB_EventType_MouseLeave      ; The mouse cursor left the gadget
      If SGs()\SelectedItem<>-1
        repaint=#True
      EndIf
      SGs()\SelectedItem=-1 
    Case  #PB_EventType_MouseMove       ; The mouse cursor moved
      If SGs()\SelectedItem<>-1
        repaint=#True
      EndIf
    Case  #PB_EventType_MouseWheel      ; The mouse wheel was moved
      SetGadgetAttribute(SGs()\scrollareagadget,#PB_ScrollArea_Y,GetGadgetAttribute(SGs()\scrollareagadget,#PB_ScrollArea_Y)-(GetGadgetAttribute(SGs()\canvasgadget,#PB_Canvas_WheelDelta)*10))          
      If SGs()\SelectedItem<>-1
        repaint=#True
      EndIf
    Case  #PB_EventType_LeftButtonDown  ; The left mouse button was pressed
      SGs()\SelectedItem=-1
      ForEach SGs()\item()
        If mx>SGs()\item()\x And mx<SGs()\item()\x+SGs()\item()\w
          If my>SGs()\item()\y And my<SGs()\item()\y+SGs()\item()\h
            SGs()\SelectedItem=ListIndex(SGs()\item())
            Break
          EndIf
        EndIf
      Next
      repaint=#True
    Case  #PB_EventType_LeftButtonUp    ; The left mouse button was released
    Case  #PB_EventType_LeftClick       ; A click With the left mouse button      
      retval=#Schedule_LeftClick
    Case  #PB_EventType_LeftDoubleClick ; A double-click With the left mouse button
      retval=#Schedule_LeftDoubleClick
    Case  #PB_EventType_RightButtonDown ; The right mouse button was pressed
    Case  #PB_EventType_RightButtonUp   ; The right mouse button was released
    Case  #PB_EventType_RightClick      ; A click With the right mouse button
      retval=#Schedule_RightClick
      SGs()\SelectedItem=-1
      ForEach SGs()\item()
        If mx>SGs()\item()\x And mx<SGs()\item()\x+SGs()\item()\w
          If my>SGs()\item()\y And my<SGs()\item()\y+SGs()\item()\h
            SGs()\SelectedItem=ListIndex(SGs()\item())
            Break
          EndIf
        EndIf
      Next
      repaint=#True
    Case  #PB_EventType_RightDoubleClick; A double-click With the right mouse button
    Case  #PB_EventType_MiddleButtonDown; The middle mouse button was pressed
    Case  #PB_EventType_MiddleButtonUp  ; The middle mouse button was released
    Case  #PB_EventType_Focus           ; The gadget gained keyboard focus
    Case  #PB_EventType_LostFocus       ; The gadget lost keyboard focus
    Case  #PB_EventType_KeyDown         ; A key was pressed
    Case  #PB_EventType_KeyUp           ; A key was released
      key.l=GetGadgetAttribute(SGs()\canvasgadget,#PB_Canvas_Key)
      SelectElement(SGs()\item(),SGs()\SelectedItem)
      If key.l=#PB_Shortcut_Escape
        SGs()\item()\text=""
      ElseIf key.l=#PB_Shortcut_Return
        SGs()\SelectedItem=-1 
      ElseIf key.l=#PB_Shortcut_Delete
        If SGs()\item()\text
          SGs()\item()\text=Left(SGs()\item()\text,Len(SGs()\item()\text)-1)
        EndIf
      EndIf
      repaint=#True
    Case  #PB_EventType_Input           ; Text input was generated 
      If SGs()\SelectedItem<>-1
        char.s=Chr(GetGadgetAttribute(SGs()\canvasgadget,#PB_Canvas_Input))
        SelectElement(SGs()\item(),SGs()\SelectedItem)
        If Asc(char)=8
          If SGs()\item()\text
            SGs()\item()\text=Left(SGs()\item()\text,Len(SGs()\item()\text)-1)
          EndIf
        Else
          SGs()\item()\text+char.s
        EndIf
        repaint=#True
      EndIf
  EndSelect
  PopListPosition(SGs())
  If repaint
    ScheduleGadget_Repaint(*sg)
  EndIf
  ProcedureReturn retval
EndProcedure
Procedure ScheduleGadget(x.i, y.i, Width.i, Height.i, flags.l=#Null, DateShown.i=0, UnitsPerHour.i=4) 
  If DateShown=0
    DateShown=Date()
  EndIf
  AddElement(SGs())  
  SGs()\topgadget= CanvasGadget(#PB_Any, x, y, Width, 25,#PB_Canvas_Keyboard)
  SGs()\scrollareagadget=ScrollAreaGadget(#PB_Any, x, y+30, width, Height-30, width-50,3600)
  SGs()\canvasgadget=CanvasGadget(#PB_Any, 0, 0, width-50,3600,#PB_Canvas_Keyboard)
  SGs()\DateShown=DateShown
  SGs()\SelectedItem=-1
  SGs()\UnitsPerHour=UnitsPerHour
  CloseGadgetList()  
  ScheduleGadget_Repaint(SGs())
  ProcedureReturn SGs()
EndProcedure
Procedure ScheduleGadget_Resize(*sg,x,y,width,height)
  PushListPosition(SGs())
  ChangeCurrentElement(SGs(),*sg)
  ResizeGadget(SGs()\topgadget, x, y, Width, 25)
  ResizeGadget(SGs()\scrollareagadget, x, y+30, width, Height-30)
  SetGadgetAttribute(SGs()\scrollareagadget, #PB_ScrollArea_InnerWidth,width-50)
  ResizeGadget(SGs()\canvasgadget, 0, 0, width-50,3600)  
  PopListPosition(SGs())
  ScheduleGadget_Repaint(*sg)  
EndProcedure
Procedure ScheduleGadget_Add(*sg) 
  PushListPosition(SGs())
  ChangeCurrentElement(SGs(),*sg)
  AddElement(SGs()\item())
  SGs()\item()\time_start=Date(Year(Date()),Month(Date()),Day(Date()),Hour(Date()),0,0)
  SGs()\item()\colour=RGBA(170,170,230,200)
  SGs()\item()\text="New Meeting"
  PopListPosition(SGs())
  ScheduleGadget_Repaint(*sg)
EndProcedure
Procedure ScheduleGadget_Remove(*sg) 
  PushListPosition(SGs())
  ChangeCurrentElement(SGs(),*sg)
  If SGs()\SelectedItem=-1
    ProcedureReturn
  EndIf
  SelectElement(SGs()\item(),SGs()\SelectedItem)
  DeleteElement(SGs()\item())
  PopListPosition(SGs())
  ScheduleGadget_Repaint(*sg)
EndProcedure

Procedure ScheduleGadget_SetTime(*sg,when.i) 
  PushListPosition(SGs())
  ChangeCurrentElement(SGs(),*sg)
  SetGadgetAttribute(SGs()\scrollareagadget,#PB_ScrollArea_Y,(GetGadgetAttribute(SGs()\scrollareagadget,#PB_ScrollArea_InnerHeight)/24)*(Hour(when)-1))          
  PopListPosition(SGs())  
EndProcedure
;- Example
OpenWindow(0, 0, 0, 500, 700, "ScheduleGadget", #PB_Window_SystemMenu|#PB_Window_ScreenCentered | #PB_Window_SizeGadget | #PB_Window_MaximizeGadget)
GadgetIndex=ScheduleGadget(0,0,500,700)
ScheduleGadget_Add(GadgetIndex)
ScheduleGadget_Repaint(GadgetIndex)  
ScheduleGadget_SetTime(GadgetIndex,Date())
Repeat
  EventID=WaitWindowEvent()
  If EventID=#PB_Event_CloseWindow
    End
  ElseIf eventid=#PB_Event_SizeWindow Or eventid=#PB_Event_MaximizeWindow
    ScheduleGadget_Resize(GadgetIndex,0,0,WindowWidth(0),WindowHeight(0))
  ElseIf EventID=#PB_Event_Gadget    
    Select ScheduleGadget_HandleEvent(GadgetIndex)      
      Case #Schedule_NewEvent
      Case #Schedule_LeftClick
      Case #Schedule_LeftDoubleClick
        ScheduleGadget_Add(GadgetIndex)
      Case #Schedule_RightClick
        ScheduleGadget_Remove(GadgetIndex)        
    EndSelect
  EndIf
ForEver
Zach
Addict
Addict
Posts: 1656
Joined: Sun Dec 12, 2010 12:36 am
Location: Somewhere in the midwest
Contact:

Re: ScheduleGadget

Post by Zach »

Compiler wrote:[16:46:34] Waiting for executable to start...
[16:46:34] Executable type: Windows - x86 (32bit, Thread)
[16:46:35] Executable started.
[16:46:50] [ERROR] Line: 198
[16:46:50] [ERROR] SelectElement(): index value can not be negative.

Clicking anywhere in the program window (not the window border itself, the window content) and then hitting any key at all produced this crash.

Windows 7 x64
Purebasic x32 v4.61 Official
Image
User avatar
Kukulkan
Addict
Addict
Posts: 1352
Joined: Mon Jun 06, 2005 2:35 pm
Location: germany
Contact:

Re: ScheduleGadget

Post by Kukulkan »

I like it. There is still a lot of work needed to make this perfect, but it is a very good start.

Interesting, the time after midnight. Is it possible to make a schedule at 24:30? :wink:

The labels are somewhat confusing and the scheduled item is only movable in a 1 hour grid (15 minutes would be much better). It also should be possible to define the appointment length by grabbing the bottom of the item and relength it by mouse.

Anyway, good start!

Kukulkan
jesperbrannmark
Enthusiast
Enthusiast
Posts: 536
Joined: Mon Feb 16, 2009 10:42 am
Location: sweden
Contact:

Re: ScheduleGadget

Post by jesperbrannmark »

Yes how movable it should be is going to be controlled by the UnitsPerHour integer. So for 15 minutes this would be 4 (4 units per hour = 60/4 = 15).
I have all that in the other calendar that uses sprites, but canvasgadget have lots of benefits.
I have implemented zoom and fixed some stuff so there will be a update soon.
jesperbrannmark
Enthusiast
Enthusiast
Posts: 536
Joined: Mon Feb 16, 2009 10:42 am
Location: sweden
Contact:

ScheduleGadget distorted on PB 5.00b3 (mac)

Post by jesperbrannmark »

Anyone have any idea why this looks like crap on 5.00b3 (mac os is what i use) - is it a problem with scrollareagadget and canvasgadget in combination?
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5353
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: ScheduleGadget

Post by Kwai chang caine »

Works fine
Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
Polo
Addict
Addict
Posts: 2422
Joined: Tue May 06, 2003 5:07 pm
Location: UK

Re: ScheduleGadget

Post by Polo »

I saved you the inconvenience of submitting a bug report :)

http://www.purebasic.fr/english/viewtop ... 24&t=51447
jesperbrannmark
Enthusiast
Enthusiast
Posts: 536
Joined: Mon Feb 16, 2009 10:42 am
Location: sweden
Contact:

Re: ScheduleGadget

Post by jesperbrannmark »

Thanks. I just couldn't see what it was, thanks for finding it! (sometimes you just get blind with your own code..)
Polo
Addict
Addict
Posts: 2422
Joined: Tue May 06, 2003 5:07 pm
Location: UK

Re: ScheduleGadget

Post by Polo »

jesperbrannmark wrote:Thanks. I just couldn't see what it was, thanks for finding it! (sometimes you just get blind with your own code..)
It was a good challenge, as your code looked perfectly fine ;)
Post Reply